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