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