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