* Remove leading '|' from references if present
[citadel.git] / webcit / calendar_view.c
blob635e96a00ea3e20dd5265f3fd903077238808dd7
1 /*
2 * $Id$
4 * Handles the HTML display of calendar items.
5 */
7 #include "webcit.h"
8 #include "webserver.h"
10 /* These define how high the hour rows are in the day view */
11 #define TIMELINE 30
12 #define EXTRATIMELINE (TIMELINE / 2)
14 void embeddable_mini_calendar(int year, int month)
16 struct tm starting_tm;
17 struct tm tm;
18 time_t thetime;
19 int i;
20 time_t previous_month;
21 time_t next_month;
22 time_t colheader_time;
23 struct tm colheader_tm;
24 char colheader_label[32];
25 long weekstart = 0;
26 char url[256];
27 char div_id[256];
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);\">&laquo;</a>",
68 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
70 wc_strftime(colheader_label, sizeof colheader_label, "%B", &starting_tm);
71 wprintf("&nbsp;&nbsp;"
72 "<span class=\"mini_calendar_month_label\">"
73 "%s %d"
74 "</span>"
75 "&nbsp;&nbsp;", colheader_label, year);
77 /* Next month link */
78 localtime_r(&next_month, &tm);
79 wprintf("<a href=\"javascript:minical_change_month(%d,%d);\">&raquo;</a>",
80 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
82 wprintf("<table border=0 cellpadding=1 cellspacing=1 class=\"mini_calendar_days\">"
83 "<tr>");
84 colheader_time = thetime;
85 for (i=0; i<7; ++i) {
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]);
92 wprintf("</tr>\n");
95 /* Now do 35 or 42 days */
96 for (i = 0; i < 42; ++i) {
97 localtime_r(&thetime, &tm);
99 if (i < 35) {
101 /* Before displaying Sunday, start a new row */
102 if ((i % 7) == 0) {
103 wprintf("<tr>");
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);
111 else {
112 wprintf("<td> </td>");
115 /* After displaying one week, end the row */
116 if ((i % 7) == 6) {
117 wprintf("</tr>\n");
122 thetime += (time_t)86400; /* ahead 24 hours */
125 wprintf("</table>" /* end of inner table */
126 "</div>\n");
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"
134 " } \n"
136 div_id
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)
155 long hklen;
156 const char *HashKey;
157 void *vCal;
158 HashPos *Pos;
159 disp_cal *Cal;
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 icaltimetype today_t;
167 struct tm starting_tm;
168 struct tm ending_tm;
169 int all_day_event = 0;
170 int show_event = 0;
171 char buf[256];
172 wcsession *WCC = WC;
173 time_t tt;
175 if (GetCount(WCC->disp_cal_items) == 0) {
176 wprintf("<br /><br /><br />\n");
177 return;
181 * Create an imaginary event which spans the 24 hours of today. Any events which
182 * overlap with this one take place at least partially in this day. We have to
183 * convert it from a struct tm in order to make it UTC.
185 memset(&starting_tm, 0, sizeof(struct tm));
186 starting_tm.tm_year = year - 1900;
187 starting_tm.tm_mon = month - 1;
188 starting_tm.tm_mday = day;
189 starting_tm.tm_hour = 0;
190 starting_tm.tm_min = 0;
191 today_start_t = icaltime_from_timet_with_zone(mktime(&starting_tm), 0, icaltimezone_get_utc_timezone());
192 today_start_t.is_utc = 1;
194 memset(&ending_tm, 0, sizeof(struct tm));
195 ending_tm.tm_year = year - 1900;
196 ending_tm.tm_mon = month - 1;
197 ending_tm.tm_mday = day;
198 ending_tm.tm_hour = 23;
199 ending_tm.tm_min = 59;
200 today_end_t = icaltime_from_timet_with_zone(mktime(&ending_tm), 0, icaltimezone_get_utc_timezone());
201 today_end_t.is_utc = 1;
204 * Create another one without caring about the timezone for all day events.
206 today_t = icaltime_null_date();
207 today_t.year = year;
208 today_t.month = month;
209 today_t.day = day;
212 * Now loop through our list of events to see which ones occur today.
214 Pos = GetNewHashPos(WCC->disp_cal_items, 0);
215 while (GetNextHashPos(WCC->disp_cal_items, Pos, &hklen, &HashKey, &vCal)) {
216 Cal = (disp_cal*)vCal;
217 all_day_event = 0;
218 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
219 if (q != NULL) {
220 t = icalproperty_get_dtstart(q);
222 else {
223 memset(&t, 0, sizeof t);
225 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
226 if (q != NULL) {
227 end_t = icalproperty_get_dtend(q);
229 else {
230 memset(&end_t, 0, sizeof end_t);
232 if (t.is_date) all_day_event = 1;
234 if (all_day_event)
236 show_event = ical_ctdl_is_overlap(t, end_t, today_t, icaltime_null_time());
238 else
240 show_event = ical_ctdl_is_overlap(t, end_t, today_start_t, today_end_t);
244 * If we determined that this event occurs today, then display it.
246 if (show_event) {
247 p = icalcomponent_get_first_property(Cal->cal, ICAL_SUMMARY_PROPERTY);
248 if (p != NULL) {
250 if (all_day_event) {
251 wprintf("<table border=0 cellpadding=2><TR>"
252 "<td bgcolor=\"#CCCCDD\">"
256 wprintf("<font size=\"-1\">"
257 "<a class=\"event%s\" href=\"display_edit_event?"
258 "msgnum=%ld?calview=month?year=%d?month=%d?day=%d\""
259 " btt_tooltext=\"",
260 (Cal->unread)?"_unread":"_read",
261 Cal->cal_msgnum,
262 year, month, day
265 wprintf("<i>%s: %s</i><br />", _("From"), Cal->from);
266 wprintf("<i>%s</i> ", _("Summary:"));
267 escputs((char *)icalproperty_get_comment(p));
268 wprintf("<br />");
270 q = icalcomponent_get_first_property(
271 Cal->cal,
272 ICAL_LOCATION_PROPERTY);
273 if (q) {
274 wprintf("<i>%s</i> ", _("Location:"));
275 escputs((char *)icalproperty_get_comment(q));
276 wprintf("<br />");
280 * Only show start/end times if we're actually looking at the VEVENT
281 * component. Otherwise it shows bogus dates for e.g. timezones
283 if (icalcomponent_isa(Cal->cal) == ICAL_VEVENT_COMPONENT) {
285 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
286 if (q != NULL) {
287 int no_end = 0;
289 t = icalproperty_get_dtstart(q);
290 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
291 if (q != NULL) {
292 end_t = icalproperty_get_dtend(q);
294 else {
296 * events with starting date/time equal
297 * ending date/time might get only
298 * DTSTART but no DTEND
300 no_end = 1;
303 if (t.is_date) {
304 /* all day event */
305 struct tm d_tm;
307 if (!no_end) {
308 /* end given, have to adjust it */
309 icaltime_adjust(&end_t, -1, 0, 0, 0);
311 memset(&d_tm, 0, sizeof d_tm);
312 d_tm.tm_year = t.year - 1900;
313 d_tm.tm_mon = t.month - 1;
314 d_tm.tm_mday = t.day;
315 wc_strftime(buf, sizeof buf, "%x", &d_tm);
317 if (no_end || !icaltime_compare(t, end_t)) {
318 wprintf("<i>%s</i> %s<br>",
319 _("Date:"), buf);
321 else {
322 wprintf("<i>%s</i> %s<br>",
323 _("Starting date:"), buf);
324 d_tm.tm_year = end_t.year - 1900;
325 d_tm.tm_mon = end_t.month - 1;
326 d_tm.tm_mday = end_t.day;
327 wc_strftime(buf, sizeof buf, "%x", &d_tm);
328 wprintf("<i>%s</i> %s<br>",
329 _("Ending date:"), buf);
332 else {
333 tt = icaltime_as_timet(t);
334 webcit_fmt_date(buf, tt, DATEFMT_BRIEF);
335 if (no_end || !icaltime_compare(t, end_t)) {
336 wprintf("<i>%s</i> %s<br>",
337 _("Date/time:"), buf);
339 else {
340 wprintf("<i>%s</i> %s<br>",
341 _("Starting date/time:"), buf);
342 tt = icaltime_as_timet(end_t);
343 webcit_fmt_date(buf, tt, DATEFMT_BRIEF);
344 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
352 q = icalcomponent_get_first_property(Cal->cal, ICAL_DESCRIPTION_PROPERTY);
353 if (q) {
354 wprintf("<i>%s</i> ", _("Notes:"));
355 escputs((char *)icalproperty_get_comment(q));
356 wprintf("<br />");
359 wprintf("\">");
360 escputs((char *)
361 icalproperty_get_comment(p));
362 wprintf("</a></font><br />\n");
364 if (all_day_event) {
365 wprintf("</td></tr></table>");
374 DeleteHashPos(&Pos);
379 * Display one day of a whole month view of a calendar
381 void calendar_month_view_brief_events(time_t thetime, const char *daycolor) {
382 long hklen;
383 const char *HashKey;
384 void *vCal;
385 HashPos *Pos;
386 time_t event_tt;
387 time_t event_tts;
388 time_t event_tte;
389 wcsession *WCC = WC;
390 struct tm event_tms;
391 struct tm event_tme;
392 struct tm today_tm;
393 icalproperty *p;
394 icalproperty *e;
395 struct icaltimetype t;
396 disp_cal *Cal;
397 int month, day, year;
398 int all_day_event = 0;
399 char *timeformat;
400 int time_format;
402 time_format = get_time_format_cached ();
404 if (time_format == WC_TIMEFORMAT_24) timeformat="%k:%M";
405 else timeformat="%I:%M %p";
407 localtime_r(&thetime, &today_tm);
408 month = today_tm.tm_mon + 1;
409 day = today_tm.tm_mday;
410 year = today_tm.tm_year + 1900;
412 Pos = GetNewHashPos(WCC->disp_cal_items, 0);
413 while (GetNextHashPos(WCC->disp_cal_items, Pos, &hklen, &HashKey, &vCal)) {
414 Cal = (disp_cal*)vCal;
415 p = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
416 if (p != NULL) {
417 t = icalproperty_get_dtstart(p);
418 event_tt = icaltime_as_timet(t);
419 event_tts=event_tt;
420 if (t.is_date) all_day_event = 1;
421 else all_day_event = 0;
423 if (all_day_event) {
424 gmtime_r(&event_tts, &event_tms);
426 else {
427 localtime_r(&event_tts, &event_tms);
429 /* \todo epoch &! daymask */
430 if ((event_tms.tm_year == today_tm.tm_year)
431 && (event_tms.tm_mon == today_tm.tm_mon)
432 && (event_tms.tm_mday == today_tm.tm_mday)) {
435 char sbuf[255];
436 char ebuf[255];
438 p = icalcomponent_get_first_property(
439 Cal->cal,
440 ICAL_SUMMARY_PROPERTY);
441 e = icalcomponent_get_first_property(
442 Cal->cal,
443 ICAL_DTEND_PROPERTY);
444 if ((p != NULL) && (e != NULL)) {
445 time_t difftime;
446 int hours, minutes;
447 t = icalproperty_get_dtend(e);
448 event_tte = icaltime_as_timet(t);
449 localtime_r(&event_tte, &event_tme);
450 difftime=(event_tte-event_tts)/60;
451 hours=(int)(difftime / 60);
452 minutes=difftime % 60;
453 wprintf("<tr><td bgcolor='%s'>%i:%2i</td><td bgcolor='%s'>"
454 "<font size=\"-1\">"
455 "<a class=\"event%s\" href=\"display_edit_event?msgnum=%ld?calview=calbrief?year=%s?month=%s?day=%s\">",
456 daycolor,
457 hours, minutes,
458 (Cal->unread)?"_unread":"_read",
459 daycolor,
460 Cal->cal_msgnum,
461 bstr("year"),
462 bstr("month"),
463 bstr("day")
466 escputs((char *)
467 icalproperty_get_comment(p));
468 /* \todo: allso ammitime format */
469 wc_strftime(&sbuf[0], sizeof(sbuf), timeformat, &event_tms);
470 wc_strftime(&ebuf[0], sizeof(sbuf), timeformat, &event_tme);
472 wprintf("</a></font></td>"
473 "<td bgcolor='%s'>%s</td><td bgcolor='%s'>%s</td></tr>",
474 daycolor,
475 sbuf,
476 daycolor,
477 ebuf);
485 DeleteHashPos(&Pos);
490 * view one month. pretty view
492 void calendar_month_view(int year, int month, int day) {
493 struct tm starting_tm;
494 struct tm tm;
495 time_t thetime;
496 int i;
497 time_t previous_month;
498 time_t next_month;
499 time_t colheader_time;
500 struct tm colheader_tm;
501 char colheader_label[32];
502 long weekstart = 0;
505 * Determine what day to start. If an impossible value is found, start on Sunday.
507 get_pref_long("weekstart", &weekstart, 17);
508 if (weekstart > 6) weekstart = 0;
511 * Now back up to the 1st of the month...
513 memset(&starting_tm, 0, sizeof(struct tm));
515 starting_tm.tm_year = year - 1900;
516 starting_tm.tm_mon = month - 1;
517 starting_tm.tm_mday = day;
518 thetime = mktime(&starting_tm);
520 memcpy(&tm, &starting_tm, sizeof(struct tm));
521 while (tm.tm_mday != 1) {
522 thetime = thetime - (time_t)86400; /* go back 24 hours */
523 localtime_r(&thetime, &tm);
526 /* Determine previous and next months ... for links */
527 previous_month = thetime - (time_t)864000L; /* back 10 days */
528 next_month = thetime + (time_t)(31L * 86400L); /* ahead 31 days */
530 /* Now back up until we're on the user's preferred start day */
531 localtime_r(&thetime, &tm);
532 while (tm.tm_wday != weekstart) {
533 thetime = thetime - (time_t)86400; /* go back 24 hours */
534 localtime_r(&thetime, &tm);
537 /* Outer table (to get the background color) */
538 wprintf("<div class=\"fix_scrollbar_bug\">"
539 "<table class=\"calendar\"> \n <tr><td>");
541 wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
543 wprintf("<td align=center>");
545 localtime_r(&previous_month, &tm);
546 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
547 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
548 wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
550 wc_strftime(colheader_label, sizeof colheader_label, "%B", &starting_tm);
551 wprintf("&nbsp;&nbsp;"
552 "<font size=+1 color=\"#FFFFFF\">"
553 "%s %d"
554 "</font>"
555 "&nbsp;&nbsp;", colheader_label, year);
557 localtime_r(&next_month, &tm);
558 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
559 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
560 wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
562 wprintf("</td></tr></table>\n");
564 /* Inner table (the real one) */
565 wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
566 "bgcolor=#204B78 id=\"inner_month\"><tr>");
567 colheader_time = thetime;
568 for (i=0; i<7; ++i) {
569 colheader_time = thetime + (i * 86400) ;
570 localtime_r(&colheader_time, &colheader_tm);
571 wc_strftime(colheader_label, sizeof colheader_label, "%A", &colheader_tm);
572 wprintf("<th align=center width=14%%>"
573 "<font color=\"#FFFFFF\">%s</font></th>", colheader_label);
576 wprintf("</tr>\n");
579 /* Now do 35 or 42 days */
580 localtime_r(&thetime, &tm);
581 for (i = 0; i<42; ++i) {
583 /* Before displaying the first day of the week, start a new row */
584 if ((i % 7) == 0) {
585 wprintf("<tr>");
588 wprintf("<td class=\"cal%s\"><div class=\"day\">",
589 ((tm.tm_mon != month-1) ? "out" :
590 ((tm.tm_wday==0 || tm.tm_wday==6) ? "weekend" :
591 "day"))
593 if ((i==0) || (tm.tm_mday == 1)) {
594 wc_strftime(colheader_label, sizeof colheader_label, "%B", &tm);
595 wprintf("%s ", colheader_label);
597 wprintf("<a href=\"readfwd?calview=day?year=%d?month=%d?day=%d\">"
598 "%d</a></div>",
599 tm.tm_year + 1900,
600 tm.tm_mon + 1,
601 tm.tm_mday,
602 tm.tm_mday);
604 /* put the data here, stupid */
605 calendar_month_view_display_events(
606 tm.tm_year + 1900,
607 tm.tm_mon + 1,
608 tm.tm_mday
611 wprintf("</td>");
613 /* After displaying the last day of the week, end the row */
614 if ((i % 7) == 6) {
615 wprintf("</tr>\n");
618 thetime += (time_t)86400; /* ahead 24 hours */
619 localtime_r(&thetime, &tm);
621 if ( ((i % 7) == 6) && (tm.tm_mon != month-1) && (tm.tm_mday < 15) ) {
622 i = 100; /* break out of the loop */
626 wprintf("</table>" /* end of inner table */
627 "</td></tr></table>" /* end of outer table */
628 "</div>\n");
631 * Initialize the bubble tooltips.
633 * Yes, this is as stupid as it looks. Instead of just making the call
634 * to btt_enableTooltips() straight away, we have to create a timer event
635 * and let it initialize as an event after 1 millisecond. This is to
636 * work around a bug in Internet Explorer that causes it to crash if we
637 * manipulate the innerHTML of various DOM nodes while the page is still
638 * being rendered. See http://www.shaftek.org/blog/archives/000212.html
639 * for more information.
641 StrBufAppendPrintf(WC->trailing_javascript,
642 " setTimeout(\"btt_enableTooltips('inner_month')\", 1); \n"
647 * view one month. brief view
649 void calendar_brief_month_view(int year, int month, int day) {
650 struct tm starting_tm;
651 struct tm tm;
652 time_t thetime;
653 int i;
654 time_t previous_month;
655 time_t next_month;
656 char month_label[32];
658 /* Determine what day to start.
659 * First, back up to the 1st of the month...
661 memset(&starting_tm, 0, sizeof(struct tm));
662 starting_tm.tm_year = year - 1900;
663 starting_tm.tm_mon = month - 1;
664 starting_tm.tm_mday = day;
665 thetime = mktime(&starting_tm);
667 memcpy(&tm, &starting_tm, sizeof(struct tm));
668 while (tm.tm_mday != 1) {
669 thetime = thetime - (time_t)86400; /* go back 24 hours */
670 localtime_r(&thetime, &tm);
673 /* Determine previous and next months ... for links */
674 previous_month = thetime - (time_t)864000L; /* back 10 days */
675 next_month = thetime + (time_t)(31L * 86400L); /* ahead 31 days */
677 /* Now back up until we're on a Sunday */
678 localtime_r(&thetime, &tm);
679 while (tm.tm_wday != 0) {
680 thetime = thetime - (time_t)86400; /* go back 24 hours */
681 localtime_r(&thetime, &tm);
684 /* Outer table (to get the background color) */
685 wprintf("<div class=\"fix_scrollbar_bug\">"
686 "<table width=100%% border=0 cellpadding=0 cellspacing=0 "
687 "bgcolor=#204B78><TR><TD>\n");
689 wprintf("<table width=100%% border=0 cellpadding=0 cellspacing=0><tr>\n");
691 wprintf("<td align=center>");
693 localtime_r(&previous_month, &tm);
694 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
695 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
696 wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>\n");
698 wc_strftime(month_label, sizeof month_label, "%B", &tm);
699 wprintf("&nbsp;&nbsp;"
700 "<font size=+1 color=\"#FFFFFF\">"
701 "%s %d"
702 "</font>"
703 "&nbsp;&nbsp;", month_label, year);
705 localtime_r(&next_month, &tm);
706 wprintf("<a href=\"readfwd?calview=month?year=%d?month=%d?day=1\">",
707 (int)(tm.tm_year)+1900, tm.tm_mon + 1);
708 wprintf("<img align=middle src=\"static/nextdate_32x.gif\" border=0></A>\n");
710 wprintf("</td></tr></table>\n");
712 /* Inner table (the real one) */
713 wprintf("<table width=100%% border=0 cellpadding=1 cellspacing=1 "
714 "bgcolor=#EEEECC><TR>");
715 wprintf("</tr>\n");
716 wprintf("<tr><td colspan=\"100%%\">\n");
718 /* Now do 35 days */
719 for (i = 0; i < 35; ++i) {
720 char weeknumber[255];
721 char weekday_name[32];
722 char *daycolor;
723 localtime_r(&thetime, &tm);
726 /* Before displaying Sunday, start a new CELL */
727 if ((i % 7) == 0) {
728 wc_strftime(&weeknumber[0], sizeof(weeknumber), "%U", &tm);
729 wprintf("<table border='0' bgcolor=\"#EEEECC\" width='100%%'> <tr><th colspan='4'>%s %s</th></tr>"
730 " <tr><td>%s</td><td width=70%%>%s</td><td>%s</td><td>%s</td></tr>\n",
731 _("Week"),
732 weeknumber,
733 _("Hours"),
734 _("Subject"),
735 _("Start"),
736 _("End")
740 daycolor=((tm.tm_mon != month-1) ? "DDDDDD" :
741 ((tm.tm_wday==0 || tm.tm_wday==6) ? "EEEECC" :
742 "FFFFFF"));
744 /* Day Header */
745 wc_strftime(weekday_name, sizeof weekday_name, "%A", &tm);
746 wprintf("<tr><td bgcolor='%s' colspan='1' align='left'> %s,%i."
747 "</td><td bgcolor='%s' colspan='3'><hr></td></tr>\n",
748 daycolor,
749 weekday_name,tm.tm_mday,
750 daycolor);
752 /* put the data of one day here, stupid */
753 calendar_month_view_brief_events(thetime, daycolor);
756 /* After displaying Saturday, end the row */
757 if ((i % 7) == 6) {
758 wprintf("</td></tr></table>\n");
761 thetime += (time_t)86400; /* ahead 24 hours */
764 wprintf("</table>" /* end of inner table */
765 "</td></tr></table>" /* end of outer table */
766 "</div>\n");
770 * Calendar week view -- not implemented yet, this is a stub function
772 void calendar_week_view(int year, int month, int day) {
773 wprintf("<center><i>week view FIXME</i></center><br />\n");
778 * display one day
779 * Display events for a particular hour of a particular day.
780 * (Specify hour < 0 to show "all day" events)
782 * dstart and dend indicate which hours our "daytime" begins and end
784 void calendar_day_view_display_events(time_t thetime,
785 int year,
786 int month,
787 int day,
788 int notime_events,
789 int dstart,
790 int dend)
792 long hklen;
793 const char *HashKey;
794 void *vCal;
795 HashPos *Pos;
796 icalproperty *p = NULL;
797 icalproperty *q = NULL;
798 time_t event_tt;
799 time_t event_tte;
800 struct tm event_te;
801 struct tm event_tm;
802 int show_event = 0;
803 int all_day_event = 0;
804 int ongoing_event = 0;
805 wcsession *WCC = WC;
806 disp_cal *Cal;
807 struct icaltimetype t;
808 struct icaltimetype end_t;
809 struct icaltimetype today_start_t;
810 struct icaltimetype today_end_t;
811 struct icaltimetype today_t;
812 struct tm starting_tm;
813 struct tm ending_tm;
814 int top = 0;
815 int bottom = 0;
816 int gap = 1;
817 int startmin = 0;
818 int diffmin = 0;
819 int endmin = 0;
821 char buf[256];
823 if (GetCount(WCC->disp_cal_items) == 0) {
824 /* nothing to display */
825 return;
828 /* Create an imaginary event which spans the current day. Any events which
829 * overlap with this one take place at least partially in this day.
831 memset(&starting_tm, 0, sizeof(struct tm));
832 starting_tm.tm_year = year - 1900;
833 starting_tm.tm_mon = month - 1;
834 starting_tm.tm_mday = day;
835 starting_tm.tm_hour = 0;
836 starting_tm.tm_min = 0;
837 today_start_t = icaltime_from_timet_with_zone(mktime(&starting_tm), 0, icaltimezone_get_utc_timezone());
838 today_start_t.is_utc = 1;
840 memset(&ending_tm, 0, sizeof(struct tm));
841 ending_tm.tm_year = year - 1900;
842 ending_tm.tm_mon = month - 1;
843 ending_tm.tm_mday = day;
844 ending_tm.tm_hour = 23;
845 ending_tm.tm_min = 59;
846 today_end_t = icaltime_from_timet_with_zone(mktime(&ending_tm), 0, icaltimezone_get_utc_timezone());
847 today_end_t.is_utc = 1;
850 * Create another one without caring about the timezone for all day events.
852 today_t = icaltime_null_date();
853 today_t.year = year;
854 today_t.month = month;
855 today_t.day = day;
857 /* Now loop through our list of events to see which ones occur today.
859 Pos = GetNewHashPos(WCC->disp_cal_items, 0);
860 while (GetNextHashPos(WCC->disp_cal_items, Pos, &hklen, &HashKey, &vCal)) {
861 Cal = (disp_cal*)vCal;
863 all_day_event = 0;
864 ongoing_event=0;
866 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
867 if (q != NULL) {
868 t = icalproperty_get_dtstart(q);
869 event_tt = icaltime_as_timet(t);
870 localtime_r(&event_tt, &event_te);
872 else {
873 memset(&t, 0, sizeof t);
876 if (t.is_date) all_day_event = 1;
878 q = icalcomponent_get_first_property(Cal->cal, ICAL_DTEND_PROPERTY);
879 if (q != NULL) {
880 end_t = icalproperty_get_dtend(q);
882 else {
883 /* no end given means end = start */
884 memcpy(&end_t, &t, sizeof(struct icaltimetype));
887 if (all_day_event)
889 show_event = ical_ctdl_is_overlap(t, end_t, today_t, icaltime_null_time());
890 if (icaltime_compare(t, end_t)) {
892 * the end date is non-inclusive so adjust it by one
893 * day because our test is inclusive, note that a day is
894 * not to much because we are talking about all day
895 * events
897 icaltime_adjust(&end_t, -1, 0, 0, 0);
900 else
902 show_event = ical_ctdl_is_overlap(t, end_t, today_start_t, today_end_t);
905 event_tte = icaltime_as_timet(end_t);
906 localtime_r(&event_tte, &event_tm);
908 /* If we determined that this event occurs today, then display it.
910 p = icalcomponent_get_first_property(Cal->cal,ICAL_SUMMARY_PROPERTY);
912 if ((show_event) && (p != NULL)) {
914 if ((event_te.tm_mday != day) || (event_tm.tm_mday != day)) ongoing_event = 1;
916 if (all_day_event && notime_events)
918 wprintf("<li class=\"event_framed%s\"> "
919 "<a href=\"display_edit_event?"
920 "msgnum=%ld?calview=day?year=%d?month=%d?day=%d\" "
921 " class=\"event_title\" "
922 " btt_tooltext=\"",
923 (Cal->unread)?"_unread":"_read",
924 Cal->cal_msgnum, year, month, day);
925 wprintf("<i>%s</i><br />", _("All day event"));
926 wprintf("<i>%s: %s</i><br />", _("From"), Cal->from);
927 wprintf("<i>%s</i> ", _("Summary:"));
928 escputs((char *) icalproperty_get_comment(p));
929 wprintf("<br />");
930 q = icalcomponent_get_first_property(Cal->cal,ICAL_LOCATION_PROPERTY);
931 if (q) {
932 wprintf("<i>%s</i> ", _("Location:"));
933 escputs((char *)icalproperty_get_comment(q));
934 wprintf("<br />");
936 if (!icaltime_compare(t, end_t)) { /* one day only */
937 webcit_fmt_date(buf, event_tt, DATEFMT_LOCALEDATE);
938 wprintf("<i>%s</i> %s<br>", _("Date:"), buf);
940 else {
941 webcit_fmt_date(buf, event_tt, DATEFMT_LOCALEDATE);
942 wprintf("<i>%s</i> %s<br>", _("Starting date:"), buf);
943 webcit_fmt_date(buf, event_tte, DATEFMT_LOCALEDATE);
944 wprintf("<i>%s</i> %s<br>", _("Ending date:"), buf);
946 q = icalcomponent_get_first_property(Cal->cal,ICAL_DESCRIPTION_PROPERTY);
947 if (q) {
948 wprintf("<i>%s</i> ", _("Notes:"));
949 escputs((char *)icalproperty_get_comment(q));
950 wprintf("<br />");
952 wprintf("\">");
953 escputs((char *) icalproperty_get_comment(p));
954 wprintf("</a> <span>(");
955 wprintf(_("All day event"));
956 wprintf(")</span></li>\n");
958 else if (ongoing_event && notime_events)
960 wprintf("<li class=\"event_framed%s\"> "
961 "<a href=\"display_edit_event?"
962 "msgnum=%ld&calview=day?year=%d?month=%d?day=%d\" "
963 " class=\"event_title\" "
964 "btt_tooltext=\"",
965 (Cal->unread)?"_unread":"_read",
966 Cal->cal_msgnum, year, month, day);
967 wprintf("<i>%s</i><br />", _("Ongoing event"));
968 wprintf("<i>%s: %s</i><br />", _("From"), Cal->from);
969 wprintf("<i>%s</i> ", _("Summary:"));
970 escputs((char *) icalproperty_get_comment(p));
971 wprintf("<br />");
972 q = icalcomponent_get_first_property(Cal->cal,ICAL_LOCATION_PROPERTY);
973 if (q) {
974 wprintf("<i>%s</i> ", _("Location:"));
975 escputs((char *)icalproperty_get_comment(q));
976 wprintf("<br />");
978 webcit_fmt_date(buf, event_tt, DATEFMT_BRIEF);
979 wprintf("<i>%s</i> %s<br>", _("Starting date/time:"), buf);
980 webcit_fmt_date(buf, event_tte, DATEFMT_BRIEF);
981 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
982 q = icalcomponent_get_first_property(Cal->cal,ICAL_DESCRIPTION_PROPERTY);
983 if (q) {
984 wprintf("<i>%s</i> ", _("Notes:"));
985 escputs((char *)icalproperty_get_comment(q));
986 wprintf("<br />");
988 wprintf("\">");
989 escputs((char *) icalproperty_get_comment(p));
990 wprintf("</a> <span>(");
991 wprintf(_("Ongoing event"));
992 wprintf(")</span></li>\n");
994 else if (!all_day_event && !notime_events)
996 gap++;
998 if (event_te.tm_mday != day) event_te.tm_hour = 0;
999 if (event_tm.tm_mday != day) event_tm.tm_hour = 24;
1001 /* Calculate the location of the top of the box */
1002 if (event_te.tm_hour < dstart) {
1003 startmin = diffmin = event_te.tm_min / 6;
1004 top = (event_te.tm_hour * EXTRATIMELINE) + startmin;
1006 else if ((event_te.tm_hour >= dstart) && (event_te.tm_hour <= dend)) {
1007 startmin = diffmin = (event_te.tm_min / 2);
1008 top = (dstart * EXTRATIMELINE) + ((event_te.tm_hour - dstart) * TIMELINE) + startmin;
1010 else if (event_te.tm_hour >dend) {
1011 startmin = diffmin = event_te.tm_min / 6;
1012 top = (dstart * EXTRATIMELINE) + ((dend - dstart - 1) * TIMELINE) + ((event_tm.tm_hour - dend + 1) * EXTRATIMELINE) + startmin ;
1014 else {
1015 /* should never get here */
1018 /* Calculate the location of the bottom of the box */
1019 if (event_tm.tm_hour < dstart) {
1020 endmin = diffmin = event_tm.tm_min / 6;
1021 bottom = (event_tm.tm_hour * EXTRATIMELINE) + endmin;
1023 else if ((event_tm.tm_hour >= dstart) && (event_tm.tm_hour <= dend)) {
1024 endmin = diffmin = (event_tm.tm_min / 2);
1025 bottom = (dstart * EXTRATIMELINE) + ((event_tm.tm_hour - dstart) * TIMELINE) + endmin ;
1027 else if (event_tm.tm_hour >dend) {
1028 endmin = diffmin = event_tm.tm_min / 6;
1029 bottom = (dstart * EXTRATIMELINE) + ((dend - dstart + 1) * TIMELINE) + ((event_tm.tm_hour - dend - 1) * EXTRATIMELINE) + endmin;
1031 else {
1032 /* should never get here */
1035 wprintf("<dd class=\"event_framed%s\" "
1036 "style=\"position: absolute; "
1037 "top:%dpx; left:%dpx; "
1038 "height:%dpx; \" >",
1039 (Cal->unread)?"_unread":"_read",
1040 top, (gap * 40), (bottom-top)
1042 wprintf("<a href=\"display_edit_event?"
1043 "msgnum=%ld?calview=day?year=%d?month=%d?day=%d?hour=%d\" "
1044 "class=\"event_title\" "
1045 "btt_tooltext=\"",
1046 Cal->cal_msgnum, year, month, day, t.hour);
1047 wprintf("<i>%s: %s</i><br />", _("From"), Cal->from);
1048 wprintf("<i>%s</i> ", _("Summary:"));
1049 escputs((char *) icalproperty_get_comment(p));
1050 wprintf("<br />");
1051 q = icalcomponent_get_first_property(Cal->cal,ICAL_LOCATION_PROPERTY);
1052 if (q) {
1053 wprintf("<i>%s</i> ", _("Location:"));
1054 escputs((char *)icalproperty_get_comment(q));
1055 wprintf("<br />");
1057 if (!icaltime_compare(t, end_t)) { /* one day only */
1058 webcit_fmt_date(buf, event_tt, DATEFMT_BRIEF);
1059 wprintf("<i>%s</i> %s<br>", _("Date/time:"), buf);
1061 else {
1062 webcit_fmt_date(buf, event_tt, DATEFMT_BRIEF);
1063 wprintf("<i>%s</i> %s<br>", _("Starting date/time:"), buf);
1064 webcit_fmt_date(buf, event_tte, DATEFMT_BRIEF);
1065 wprintf("<i>%s</i> %s<br>", _("Ending date/time:"), buf);
1067 q = icalcomponent_get_first_property(Cal->cal,ICAL_DESCRIPTION_PROPERTY);
1068 if (q) {
1069 wprintf("<i>%s</i> ", _("Notes:"));
1070 escputs((char *)icalproperty_get_comment(q));
1071 wprintf("<br />");
1073 wprintf("\">");
1075 escputs((char *) icalproperty_get_comment(p));
1076 wprintf("</a></dd>\n");
1080 DeleteHashPos(&Pos);
1084 * view one day
1086 void calendar_day_view(int year, int month, int day) {
1087 int hour;
1088 struct icaltimetype today, yesterday, tomorrow;
1089 long daystart;
1090 long dayend;
1091 struct tm d_tm;
1092 char d_str[128];
1093 int time_format;
1094 time_t today_t;
1095 int timeline = TIMELINE;
1096 int extratimeline = EXTRATIMELINE;
1097 int gap = 0;
1098 int hourlabel;
1099 int extrahourlabel;
1101 time_format = get_time_format_cached ();
1102 get_pref_long("daystart", &daystart, 8);
1103 get_pref_long("dayend", &dayend, 17);
1105 /* when loading daystart/dayend, replace missing, corrupt, or impossible values with defaults */
1106 if ((daystart < 0) || (dayend < 2) || (daystart >= 23) || (dayend > 23) || (dayend <= daystart)) {
1107 daystart = 9;
1108 dayend = 17;
1111 /* Today's date */
1112 memset(&d_tm, 0, sizeof d_tm);
1113 d_tm.tm_year = year - 1900;
1114 d_tm.tm_mon = month - 1;
1115 d_tm.tm_mday = day;
1116 today_t = mktime(&d_tm);
1118 /* Figure out the dates for "yesterday" and "tomorrow" links */
1120 memset(&today, 0, sizeof(struct icaltimetype));
1121 today.year = year;
1122 today.month = month;
1123 today.day = day;
1124 today.is_date = 1;
1126 memcpy(&yesterday, &today, sizeof(struct icaltimetype));
1127 --yesterday.day;
1128 yesterday = icaltime_normalize(yesterday);
1130 memcpy(&tomorrow, &today, sizeof(struct icaltimetype));
1131 ++tomorrow.day;
1132 tomorrow = icaltime_normalize(tomorrow);
1134 wprintf("<div class=\"fix_scrollbar_bug\">");
1136 /* Inner table (the real one) */
1137 wprintf("<table class=\"calendar\" id=\"inner_day\"><tr> \n");
1139 /* Innermost cell (contains hours etc.) */
1140 wprintf("<td class=\"events_of_the_day\" >");
1141 wprintf("<dl class=\"events\" >");
1143 /* Now the middle of the day... */
1145 extrahourlabel = extratimeline - 2;
1146 hourlabel = extrahourlabel * 150 / 100;
1147 if (hourlabel > (timeline - 2)) hourlabel = timeline - 2;
1149 for (hour = 0; hour < daystart; ++hour) { /* could do HEIGHT=xx */
1150 wprintf("<dt class=\"extrahour\" "
1151 "style=\" "
1152 "position: absolute; "
1153 "top: %dpx; left: 0px; "
1154 "height: %dpx; "
1155 "font-size: %dpx; "
1156 "\" > "
1157 "<a href=\"display_edit_event?msgnum=0"
1158 "?calview=day?year=%d?month=%d?day=%d?hour=%d?minute=0\">",
1159 (hour * extratimeline ),
1160 extratimeline,
1161 extrahourlabel,
1162 year, month, day, hour
1165 if (time_format == WC_TIMEFORMAT_24) {
1166 wprintf("%2d:00</a> ", hour);
1168 else {
1169 wprintf("%d:00%s</a> ",
1170 ((hour == 0) ? 12 : (hour <= 12 ? hour : hour-12)),
1171 (hour < 12 ? "am" : "pm")
1175 wprintf("</dt>");
1178 gap = daystart * extratimeline;
1180 for (hour = daystart; hour <= dayend; ++hour) { /* could do HEIGHT=xx */
1181 wprintf("<dt class=\"hour\" "
1182 "style=\" "
1183 "position: absolute; "
1184 "top: %ldpx; left: 0px; "
1185 "height: %dpx; "
1186 "font-size: %dpx; "
1187 "\" > "
1188 "<a href=\"display_edit_event?msgnum=0?calview=day"
1189 "?year=%d?month=%d?day=%d?hour=%d?minute=0\">",
1190 gap + ((hour - daystart) * timeline ),
1191 timeline,
1192 hourlabel,
1193 year, month, day, hour
1196 if (time_format == WC_TIMEFORMAT_24) {
1197 wprintf("%2d:00</a> ", hour);
1199 else {
1200 wprintf("%d:00%s</a> ",
1201 (hour <= 12 ? hour : hour-12),
1202 (hour < 12 ? "am" : "pm")
1206 wprintf("</dt>");
1209 gap = gap + ((dayend - daystart + 1) * timeline);
1211 for (hour = (dayend + 1); hour < 24; ++hour) { /* could do HEIGHT=xx */
1212 wprintf("<dt class=\"extrahour\" "
1213 "style=\" "
1214 "position: absolute; "
1215 "top: %ldpx; left: 0px; "
1216 "height: %dpx; "
1217 "font-size: %dpx; "
1218 "\" > "
1219 "<a href=\"display_edit_event?msgnum=0?calview=day"
1220 "?year=%d?month=%d?day=%d?hour=%d?minute=0\">",
1221 gap + ((hour - dayend - 1) * extratimeline ),
1222 extratimeline,
1223 extrahourlabel,
1224 year, month, day, hour
1227 if (time_format == WC_TIMEFORMAT_24) {
1228 wprintf("%2d:00</a> ", hour);
1230 else {
1231 wprintf("%d:00%s</a> ",
1232 (hour <= 12 ? hour : hour-12),
1233 (hour < 12 ? "am" : "pm")
1237 wprintf("</dt>");
1240 /* Display events with start and end times on this day */
1241 calendar_day_view_display_events(today_t, year, month, day, 0, daystart, dayend);
1243 wprintf("</dl>");
1244 wprintf("</td>"); /* end of innermost table */
1246 /* Display extra events (start/end times not present or not today) in the middle column */
1247 wprintf("<td class=\"extra_events\">");
1249 wprintf("<ul>");
1251 /* Display all-day events */
1252 calendar_day_view_display_events(today_t, year, month, day, 1, daystart, dayend);
1254 wprintf("</ul>");
1256 wprintf("</td>"); /* end extra on the middle */
1258 wprintf("<td width=20%% align=center valign=top>"); /* begin stuff-on-the-right */
1260 /* Begin todays-date-with-left-and-right-arrows */
1261 wprintf("<table border=0 width=100%% "
1262 "cellspacing=0 cellpadding=0 bgcolor=\"#FFFFFF\">\n");
1263 wprintf("<tr>");
1265 /* Left arrow */
1266 wprintf("<td align=center>");
1267 wprintf("<a href=\"readfwd?calview=day?year=%d?month=%d?day=%d\">",
1268 yesterday.year, yesterday.month, yesterday.day);
1269 wprintf("<img align=middle src=\"static/prevdate_32x.gif\" border=0></A>");
1270 wprintf("</td>");
1272 wc_strftime(d_str, sizeof d_str,
1273 "<td align=center>"
1274 "<font size=+2>%B</font><br />"
1275 "<font size=+3>%d</font><br />"
1276 "<font size=+2>%Y</font><br />"
1277 "</td>",
1278 &d_tm
1280 wprintf("%s", d_str);
1282 /* Right arrow */
1283 wprintf("<td align=center>");
1284 wprintf("<a href=\"readfwd?calview=day?year=%d?month=%d?day=%d\">",
1285 tomorrow.year, tomorrow.month, tomorrow.day);
1286 wprintf("<img align=middle src=\"static/nextdate_32x.gif\""
1287 " border=0></a>\n");
1288 wprintf("</td>");
1290 wprintf("</tr></table>\n");
1291 /* End todays-date-with-left-and-right-arrows */
1293 /* Embed a mini month calendar in this space */
1294 wprintf("<br />\n");
1295 embeddable_mini_calendar(year, month);
1297 wprintf("</font></center>\n");
1299 wprintf("</td></tr>"); /* end stuff-on-the-right */
1301 wprintf("</table>" /* end of inner table */
1302 "</div>");
1304 StrBufAppendPrintf(WC->trailing_javascript,
1305 " setTimeout(\"btt_enableTooltips('inner_day')\", 1); \n"
1311 * Display today's events. Returns the number of items displayed.
1313 int calendar_summary_view(void) {
1314 long hklen;
1315 const char *HashKey;
1316 void *vCal;
1317 HashPos *Pos;
1318 disp_cal *Cal;
1319 icalproperty *p;
1320 struct icaltimetype t;
1321 time_t event_tt;
1322 struct tm event_tm;
1323 struct tm today_tm;
1324 time_t now;
1325 int all_day_event = 0;
1326 char timestring[SIZ];
1327 wcsession *WCC = WC;
1328 int num_displayed = 0;
1330 if (GetCount(WC->disp_cal_items) == 0) {
1331 return(0);
1334 now = time(NULL);
1335 localtime_r(&now, &today_tm);
1337 Pos = GetNewHashPos(WCC->disp_cal_items, 0);
1338 while (GetNextHashPos(WCC->disp_cal_items, Pos, &hklen, &HashKey, &vCal)) {
1339 Cal = (disp_cal*)vCal;
1340 p = icalcomponent_get_first_property(Cal->cal, ICAL_DTSTART_PROPERTY);
1341 if (p != NULL) {
1342 t = icalproperty_get_dtstart(p);
1343 event_tt = icaltime_as_timet(t);
1344 if (t.is_date) {
1345 all_day_event = 1;
1347 else {
1348 all_day_event = 0;
1350 fmt_time(timestring, event_tt);
1352 if (all_day_event) {
1353 gmtime_r(&event_tt, &event_tm);
1355 else {
1356 localtime_r(&event_tt, &event_tm);
1359 if ( (event_tm.tm_year == today_tm.tm_year)
1360 && (event_tm.tm_mon == today_tm.tm_mon)
1361 && (event_tm.tm_mday == today_tm.tm_mday)
1364 p = icalcomponent_get_first_property(Cal->cal, ICAL_SUMMARY_PROPERTY);
1365 if (p != NULL) {
1368 if (WCC->wc_view == VIEW_TASKS) {
1369 wprintf("<a href=\"display_edit_task"
1370 "?msgnum=%ld"
1371 "?return_to_summary=1"
1372 "?gotofirst=",
1373 Cal->cal_msgnum
1375 escputs(ChrPtr(WCC->wc_roomname));
1376 wprintf("\">");
1378 else {
1379 wprintf("<a href=\"display_edit_event"
1380 "?msgnum=%ld"
1381 "?calview=summary"
1382 "?year=%d"
1383 "?month=%d"
1384 "?day=%d"
1385 "?gotofirst=",
1386 Cal->cal_msgnum,
1387 today_tm.tm_year + 1900,
1388 today_tm.tm_mon + 1,
1389 today_tm.tm_mday
1391 escputs(ChrPtr(WCC->wc_roomname));
1392 wprintf("\">");
1394 escputs((char *) icalproperty_get_comment(p));
1395 if (!all_day_event) {
1396 wprintf(" (%s)", timestring);
1398 wprintf("</a><br />\n");
1399 ++num_displayed;
1404 DeleteHashPos(&Pos);
1405 DeleteHash(&WC->disp_cal_items);
1406 return(num_displayed);
1410 * Parse the URL variables in order to determine the scope and display of a calendar view
1412 void parse_calendar_view_request(struct calview *c) {
1413 time_t now;
1414 struct tm tm;
1415 char calview[32];
1416 int span = 3888000;
1418 /* In case no date was specified, go with today */
1419 now = time(NULL);
1420 localtime_r(&now, &tm);
1421 c->year = tm.tm_year + 1900;
1422 c->month = tm.tm_mon + 1;
1423 c->day = tm.tm_mday;
1425 /* Now see if a date was specified */
1426 if (havebstr("year")) c->year = ibstr("year");
1427 if (havebstr("month")) c->month = ibstr("month");
1428 if (havebstr("day")) c->day = ibstr("day");
1430 /* How would you like that cooked? */
1431 if (havebstr("calview")) {
1432 strcpy(calview, bstr("calview"));
1434 else {
1435 strcpy(calview, "month");
1438 /* Display the selected view */
1439 if (!strcasecmp(calview, "day")) {
1440 c->view = calview_day;
1442 else if (!strcasecmp(calview, "week")) {
1443 c->view = calview_week;
1445 else if (!strcasecmp(calview, "summary")) { /* shouldn't ever happen, but just in case */
1446 c->view = calview_day;
1448 else {
1449 if (WC->wc_view == VIEW_CALBRIEF) {
1450 c->view = calview_brief;
1452 else {
1453 c->view = calview_month;
1457 /* Now try and set the lower and upper bounds so that we don't
1458 * burn too many cpu cycles parsing data way in the past or future
1461 tm.tm_year = c->year - 1900;
1462 tm.tm_mon = c->month - 1;
1463 tm.tm_mday = c->day;
1464 now = mktime(&tm);
1466 if (c->view == calview_month) span = 3888000;
1467 if (c->view == calview_brief) span = 3888000;
1468 if (c->view == calview_week) span = 604800;
1469 if (c->view == calview_day) span = 86400;
1470 if (c->view == calview_summary) span = 86400;
1472 c->lower_bound = now - span;
1473 c->upper_bound = now + span;
1479 * Render a calendar view from data previously loaded into memory
1481 void render_calendar_view(struct calview *c)
1483 if (c->view == calview_day) {
1484 calendar_day_view(c->year, c->month, c->day);
1486 else if (c->view == calview_week) {
1487 calendar_week_view(c->year, c->month, c->day);
1489 else {
1490 if (WC->wc_view == VIEW_CALBRIEF) {
1491 calendar_brief_month_view(c->year, c->month, c->day);
1493 else {
1494 calendar_month_view(c->year, c->month, c->day);
1498 /* Free the in-memory list of calendar items */
1499 DeleteHash(&WC->disp_cal_items);
1504 * Helper function for do_tasks_view(). Returns the due date/time of a vtodo.
1506 time_t get_task_due_date(icalcomponent *vtodo, int *is_date) {
1507 icalproperty *p;
1509 if (vtodo == NULL) {
1510 return(0L);
1514 * If we're looking at a fully encapsulated VCALENDAR
1515 * rather than a VTODO component, recurse into the data
1516 * structure until we get a VTODO.
1518 if (icalcomponent_isa(vtodo) == ICAL_VCALENDAR_COMPONENT) {
1519 return get_task_due_date(
1520 icalcomponent_get_first_component(
1521 vtodo, ICAL_VTODO_COMPONENT
1522 ), is_date
1526 p = icalcomponent_get_first_property(vtodo, ICAL_DUE_PROPERTY);
1527 if (p != NULL) {
1528 struct icaltimetype t = icalproperty_get_due(p);
1530 if (is_date)
1531 *is_date = t.is_date;
1532 return(icaltime_as_timet(t));
1534 else {
1535 return(0L);
1541 * Compare the due dates of two tasks (this is for sorting)
1543 int task_due_cmp(const void *vtask1, const void *vtask2) {
1544 disp_cal * Task1 = (disp_cal *)GetSearchPayload(vtask1);
1545 disp_cal * Task2 = (disp_cal *)GetSearchPayload(vtask2);
1547 time_t t1;
1548 time_t t2;
1550 t1 = get_task_due_date(Task1->cal, NULL);
1551 t2 = get_task_due_date(Task2->cal, NULL);
1552 if (t1 < t2) return(-1);
1553 if (t1 > t2) return(1);
1554 return(0);
1558 * qsort filter to move completed tasks to bottom of task list
1560 int task_completed_cmp(const void *vtask1, const void *vtask2) {
1561 disp_cal * Task1 = (disp_cal *)GetSearchPayload(vtask1);
1562 /* disp_cal * Task2 = (disp_cal *)GetSearchPayload(vtask2); */
1564 icalproperty_status t1 = icalcomponent_get_status((Task1)->cal);
1565 /* icalproperty_status t2 = icalcomponent_get_status(((struct disp_cal *)task2)->cal); */
1567 if (t1 == ICAL_STATUS_COMPLETED)
1568 return 1;
1569 return 0;
1575 * do the whole task view stuff
1577 void do_tasks_view(void) {
1578 long hklen;
1579 const char *HashKey;
1580 void *vCal;
1581 disp_cal *Cal;
1582 HashPos *Pos;
1583 int nItems;
1584 time_t due;
1585 char buf[SIZ];
1586 icalproperty *p;
1587 wcsession *WCC = WC;
1589 wprintf("<div class=\"fix_scrollbar_bug\">"
1590 "<table class=\"calendar_view_background\"><tbody id=\"taskview\">\n<tr>\n"
1591 "<th>");
1592 wprintf(_("Completed?"));
1593 wprintf("</th><th>");
1594 wprintf(_("Name of task"));
1595 wprintf("</th><th>");
1596 wprintf(_("Date due"));
1597 wprintf("</th><th>");
1598 wprintf(_("Category"));
1599 wprintf(" (<select id=\"selectcategory\"><option value=\"showall\">%s</option></select>)</th></tr>\n",
1600 _("Show All"));
1602 nItems = GetCount(WC->disp_cal_items);
1604 /* Sort them if necessary
1605 if (nItems > 1) {
1606 SortByPayload(WC->disp_cal_items, task_due_cmp);
1608 * this shouldn't be neccessary, since we sort by the start time.
1611 /* And then again, by completed */
1612 if (nItems > 1) {
1613 SortByPayload(WC->disp_cal_items,
1614 task_completed_cmp);
1617 Pos = GetNewHashPos(WCC->disp_cal_items, 0);
1618 while (GetNextHashPos(WCC->disp_cal_items, Pos, &hklen, &HashKey, &vCal)) {
1619 icalproperty_status todoStatus;
1620 int is_date;
1622 Cal = (disp_cal*)vCal;
1623 wprintf("<tr><td>");
1624 todoStatus = icalcomponent_get_status(Cal->cal);
1625 wprintf("<input type=\"checkbox\" name=\"completed\" value=\"completed\" ");
1626 if (todoStatus == ICAL_STATUS_COMPLETED) {
1627 wprintf("checked=\"checked\" ");
1629 wprintf("disabled=\"disabled\">\n</td><td>");
1630 p = icalcomponent_get_first_property(Cal->cal,
1631 ICAL_SUMMARY_PROPERTY);
1632 wprintf("<a href=\"display_edit_task?msgnum=%ld?taskrm=", Cal->cal_msgnum);
1633 urlescputs(ChrPtr(WC->wc_roomname));
1634 wprintf("\">");
1635 /* wprintf("<img align=middle "
1636 "src=\"static/taskmanag_16x.gif\" border=0>&nbsp;"); */
1637 if (p != NULL) {
1638 escputs((char *)icalproperty_get_comment(p));
1640 wprintf("</a>\n");
1641 wprintf("</td>\n");
1643 due = get_task_due_date(Cal->cal, &is_date);
1644 wprintf("<td><span");
1645 if (due > 0) {
1646 webcit_fmt_date(buf, due, is_date ? DATEFMT_RAWDATE : DATEFMT_FULL);
1647 wprintf(">%s",buf);
1649 else {
1650 wprintf(">");
1652 wprintf("</span></td>");
1653 wprintf("<td>");
1654 p = icalcomponent_get_first_property(Cal->cal,
1655 ICAL_CATEGORIES_PROPERTY);
1656 if (p != NULL) {
1657 escputs((char *)icalproperty_get_categories(p));
1659 wprintf("</td>");
1660 wprintf("</tr>");
1663 wprintf("</tbody></table></div>\n");
1665 /* Free the list */
1666 DeleteHash(&WC->disp_cal_items);
1667 DeleteHashPos(&Pos);