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