Big change to calendar view functions. We now declare
authorArt Cancro <ajc@citadel.org>
Sat, 11 Oct 2008 04:20:03 +0000 (04:20 +0000)
committerArt Cancro <ajc@citadel.org>
Sat, 11 Oct 2008 04:20:03 +0000 (04:20 +0000)
lower and upper bounds before loading calendar items into memory, so that the rendering code
doesn't have to go through thousands of recurrences that span way into the future.  Right now
it only uses this data to know when to stop iterating recurrences, but it could be fine tuned
even more to totally not store calendar items that are out of scope.

webcit/calendar.c
webcit/calendar_view.c
webcit/event.c
webcit/messages.c
webcit/summary.c
webcit/webcit.h

index b3200fcb23209708d3247736885f66fefe49399e..5daee196db08d442c427a04fe619964b499ed98b 100644 (file)
@@ -413,7 +413,7 @@ void delete_cal(void *vCal)
  * any iCalendar objects and store them in a hash table.  Later on, the second phase will
  * use this hash table to render the calendar for display.
  */
-void display_individual_cal(icalcomponent *cal, long msgnum, char *from, int unread)
+void display_individual_cal(icalcomponent *cal, long msgnum, char *from, int unread, struct calview *calv)
 {
        icalproperty *ps = NULL;
        struct icaltimetype dtstart, dtend;
@@ -492,7 +492,8 @@ void display_individual_cal(icalcomponent *cal, long msgnum, char *from, int unr
        ritr = icalrecur_iterator_new(recur, dtstart);
        if (!ritr) return;
 
-       while (next = icalrecur_iterator_next(ritr), !icaltime_is_null_time(next) ) {
+       int stop_rr = 0;
+       while (next = icalrecur_iterator_next(ritr), ((!icaltime_is_null_time(next))&&(!stop_rr)) ) {
                ++num_recur;
 
                if (num_recur > 1) {            /* Skip the first one.  We already did it at the root. */
@@ -534,6 +535,9 @@ void display_individual_cal(icalcomponent *cal, long msgnum, char *from, int unr
                                sizeof(Cal->event_start), 
                                Cal, 
                                delete_cal);
+
+                       /* If an upper bound is set, stop when we go out of scope */
+                       if (calv) if (final_recurrence > calv->upper_bound) stop_rr = 1;
                }
        }
        lprintf(9, "Performed %d recurrences; final one is %s", num_recur, ctime(&final_recurrence));
@@ -545,7 +549,8 @@ void display_individual_cal(icalcomponent *cal, long msgnum, char *from, int unr
 /*
  * Display a task by itself (for editing)
  */
-void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, char *from, int unread) 
+void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, char *from,
+                       int unread, struct calview *calv)
 {
        icalcomponent *vtodo;
        icalproperty *p;
@@ -572,8 +577,7 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
                                icalcomponent_get_first_component(
                                        vtodo, ICAL_VTODO_COMPONENT
                                        ), 
-                               msgnum,
-                               from, unread
+                               msgnum, from, unread, calv
                                );
                        return;
                }
@@ -722,7 +726,8 @@ void display_edit_individual_task(icalcomponent *supplied_vtodo, long msgnum, ch
  * \param supplied_vtodo the task to save
  * \param msgnum number of the mesage in our db
  */
-void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from, int unread) 
+void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from, int unread,
+                               struct calview *calv)
 {
        char buf[SIZ];
        int delete_existing = 0;
@@ -747,7 +752,7 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
                        save_individual_task(
                                icalcomponent_get_first_component(
                                        vtodo, ICAL_VTODO_COMPONENT), 
-                               msgnum, from, unread
+                               msgnum, from, unread, calv
                                );
                        return;
                }
@@ -909,9 +914,10 @@ void save_individual_task(icalcomponent *supplied_vtodo, long msgnum, char* from
  * the relevant part, deserialize it into a libical component, filter it for
  * the requested object type, and feed it to the specified handler.
  */
-void display_using_handler(long msgnum, int unread,
+void load_ical_object(long msgnum, int unread,
                           icalcomponent_kind which_kind,
-                          void (*callback)(icalcomponent *, long, char*, int)
+                          void (*callback)(icalcomponent *, long, char*, int, struct calview *),
+                          struct calview *calv
        ) 
 {
        char buf[1024];
@@ -962,14 +968,14 @@ void display_using_handler(long msgnum, int unread,
 
                                /* Simple components of desired type */
                                if (icalcomponent_isa(cal) == which_kind) {
-                                       callback(cal, msgnum, from, unread);
+                                       callback(cal, msgnum, from, unread, calv);
                                }
 
                                /* Subcomponents of desired type */
                                for (c = icalcomponent_get_first_component(cal, which_kind);
                                     (c != 0);
                                     c = icalcomponent_get_next_component(cal, which_kind)) {
-                                       callback(c, msgnum, from, unread);
+                                       callback(c, msgnum, from, unread, calv);
                                }
                                icalcomponent_free(cal);
                        }
@@ -982,15 +988,15 @@ void display_using_handler(long msgnum, int unread,
 /*
  * Display a calendar item
  */
-void display_calendar(long msgnum, int unread) {
-       display_using_handler(msgnum, unread, ICAL_VEVENT_COMPONENT, display_individual_cal);
+void load_calendar_item(long msgnum, int unread, struct calview *c) {
+       load_ical_object(msgnum, unread, ICAL_VEVENT_COMPONENT, display_individual_cal, c);
 }
 
 /*
  * Display task view
  */
 void display_task(long msgnum, int unread) {
-       display_using_handler(msgnum, unread, ICAL_VTODO_COMPONENT, display_individual_cal);
+       load_ical_object(msgnum, unread, ICAL_VTODO_COMPONENT, display_individual_cal, NULL);
 }
 
 /*
@@ -1007,13 +1013,15 @@ void display_edit_task(void) {
        msgnum = lbstr("msgnum");
        if (msgnum > 0L) {
                /* existing task */
-               display_using_handler(msgnum, 0,
+               load_ical_object(msgnum, 0,
                                      ICAL_VTODO_COMPONENT,
-                                     display_edit_individual_task);
+                                     display_edit_individual_task,
+                                     NULL
+               );
        }
        else {
                /* new task */
-               display_edit_individual_task(NULL, 0L, "", 0);
+               display_edit_individual_task(NULL, 0L, "", 0, NULL);
        }
 }
 
@@ -1022,13 +1030,12 @@ void display_edit_task(void) {
  */
 void save_task(void) {
        long msgnum = 0L;
-
        msgnum = lbstr("msgnum");
        if (msgnum > 0L) {
-               display_using_handler(msgnum, 0, ICAL_VTODO_COMPONENT, save_individual_task);
+               load_ical_object(msgnum, 0, ICAL_VTODO_COMPONENT, save_individual_task, NULL);
        }
        else {
-               save_individual_task(NULL, 0L, "", 0);
+               save_individual_task(NULL, 0L, "", 0, NULL);
        }
 }
 
@@ -1041,11 +1048,11 @@ void display_edit_event(void) {
        msgnum = lbstr("msgnum");
        if (msgnum > 0L) {
                /* existing event */
-               display_using_handler(msgnum, 0, ICAL_VEVENT_COMPONENT, display_edit_individual_event);
+               load_ical_object(msgnum, 0, ICAL_VEVENT_COMPONENT, display_edit_individual_event, NULL);
        }
        else {
                /* new event */
-               display_edit_individual_event(NULL, 0L, "", 0);
+               display_edit_individual_event(NULL, 0L, "", 0, NULL);
        }
 }
 
@@ -1058,10 +1065,10 @@ void save_event(void) {
        msgnum = lbstr("msgnum");
 
        if (msgnum > 0L) {
-               display_using_handler(msgnum, 0, ICAL_VEVENT_COMPONENT, save_individual_event);
+               load_ical_object(msgnum, 0, ICAL_VEVENT_COMPONENT, save_individual_event, NULL);
        }
        else {
-               save_individual_event(NULL, 0L, "", 0);
+               save_individual_event(NULL, 0L, "", 0, NULL);
        }
 }
 
index cccbdc8129c6141acc9e5975b515a2216df639fe..cf5ab1a0836ce52959aa943440f6da26bf2621f0 100644 (file)
@@ -1319,26 +1319,24 @@ void calendar_summary_view(void) {
 
 
 /*
- * do the whole calendar page
- * view any part of the calender. decide which way, etc.
+ * Parse the URL variables in order to determine the scope and display of a calendar view
  */
-void do_calendar_view(void) {
+void parse_calendar_view_request(struct calview *c) {
        time_t now;
        struct tm tm;
-       int year, month, day;
-       char calview[SIZ];
+       char calview[32];
 
        /* In case no date was specified, go with today */
        now = time(NULL);
        localtime_r(&now, &tm);
-       year = tm.tm_year + 1900;
-       month = tm.tm_mon + 1;
-       day = tm.tm_mday;
+       c->year = tm.tm_year + 1900;
+       c->month = tm.tm_mon + 1;
+       c->day = tm.tm_mday;
 
        /* Now see if a date was specified */
-       if (havebstr("year")) year = ibstr("year");
-       if (havebstr("month")) month = ibstr("month");
-       if (havebstr("day")) day = ibstr("day");
+       if (havebstr("year")) c->year = ibstr("year");
+       if (havebstr("month")) c->month = ibstr("month");
+       if (havebstr("day")) c->day = ibstr("day");
 
        /* How would you like that cooked? */
        if (havebstr("calview")) {
@@ -1350,17 +1348,58 @@ void do_calendar_view(void) {
 
        /* Display the selected view */
        if (!strcasecmp(calview, "day")) {
-               calendar_day_view(year, month, day);
+               c->view = calview_day;
        }
        else if (!strcasecmp(calview, "week")) {
-               calendar_week_view(year, month, day);
+               c->view = calview_week;
        }
        else {
                if (WC->wc_view == VIEW_CALBRIEF) {
-                       calendar_brief_month_view(year, month, day);
+                       c->view = calview_brief;
                }
                else {
-                       calendar_month_view(year, month, day);
+                       c->view = calview_month;
+               }
+       }
+
+       /* Now try and set the lower and upper bounds so that we don't
+        * burn too many cpu cycles parsing data way in the past or future
+        */
+
+       tm.tm_year = c->year - 1900;
+       tm.tm_mon = c->month - 1;
+       tm.tm_mday = c->day;
+       now = mktime(&tm);
+
+       int span = 3888000;
+       if (c->view == calview_month)   span = 3888000;
+       if (c->view == calview_brief)   span = 3888000;
+       if (c->view == calview_week)    span = 604800;
+       if (c->view == calview_day)     span = 86400;
+
+       c->lower_bound = now - span;
+       c->upper_bound = now + span;
+}
+
+
+
+/*
+ * Render a calendar view from data previously loaded into memory
+ */
+void render_calendar_view(struct calview *c)
+{
+       if (c->view == calview_day) {
+               calendar_day_view(c->year, c->month, c->day);
+       }
+       else if (c->view == calview_week) {
+               calendar_week_view(c->year, c->month, c->day);
+       }
+       else {
+               if (WC->wc_view == VIEW_CALBRIEF) {
+                       calendar_brief_month_view(c->year, c->month, c->day);
+               }
+               else {
+                       calendar_month_view(c->year, c->month, c->day);
                }
        }
 
index 9bce4ce2ac5433a4fdd164264028f7d2e4b037ed..64ea2270737829cce3287a6f4550028327d8b9e0 100644 (file)
@@ -12,7 +12,9 @@
  * supplied_vevent     the event to edit
  * msgnum              reference on the citserver
  */
-void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum, char *from, int unread) {
+void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum, char *from,
+       int unread, struct calview *calv)
+{
        icalcomponent *vevent;
        icalproperty *p;
        icalvalue *v;
@@ -70,7 +72,7 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum,
                        display_edit_individual_event(
                                icalcomponent_get_first_component(
                                        vevent, ICAL_VEVENT_COMPONENT), 
-                               msgnum, from, unread
+                               msgnum, from, unread, NULL
                        );
                        return;
                }
@@ -639,7 +641,8 @@ void display_edit_individual_event(icalcomponent *supplied_vevent, long msgnum,
  * supplied_vevent:    the event to save
  * msgnum:             the index on the citserver
  */
-void save_individual_event(icalcomponent *supplied_vevent, long msgnum, char *from, int unread) {
+void save_individual_event(icalcomponent *supplied_vevent, long msgnum, char *from,
+                       int unread, struct calview *calv) {
        char buf[SIZ];
        icalproperty *prop;
        icalcomponent *vevent, *encaps;
@@ -669,7 +672,7 @@ void save_individual_event(icalcomponent *supplied_vevent, long msgnum, char *fr
                        save_individual_event(
                                icalcomponent_get_first_component(
                                        vevent, ICAL_VEVENT_COMPONENT), 
-                               msgnum, from, unread
+                               msgnum, from, unread, NULL
                        );
                        return;
                }
@@ -933,7 +936,7 @@ STARTOVER:  for (attendee = icalcomponent_get_first_property(vevent, ICAL_ATTENDE
                        check_attendee_availability(encaps);
 
                        /** This displays the form again, with our annotations */
-                       display_edit_individual_event(encaps, msgnum, from, unread);
+                       display_edit_individual_event(encaps, msgnum, from, unread, NULL);
 
                        icalcomponent_free(encaps);
                        encaps = NULL;
index d4036a13386df7b803d25f1703e1f97fe79a06c1..ce6a3dc795f7395ca06f9469569f0343a5f367f1 100644 (file)
@@ -2445,6 +2445,7 @@ void readloop(char *oper)
        int is_addressbook = 0;
        int is_singlecard = 0;
        int is_calendar = 0;
+       struct calview calv;
        int is_tasks = 0;
        int is_notes = 0;
        int is_bbview = 0;
@@ -2567,6 +2568,7 @@ void readloop(char *oper)
                is_calendar = 1;
                strcpy(cmd, "MSGS ALL|||1");
                maxmsgs = 32767;
+               parse_calendar_view_request(&calv);
        }
        if (WCC->wc_default_view == VIEW_TASKS) {               /**< tasks */
                is_tasks = 1;
@@ -2791,7 +2793,7 @@ void readloop(char *oper)
                                addrbook[num_ab-1].ab_msgnum = WCC->msgarr[a];
                        }
                        else if (is_calendar) {
-                               display_calendar(WCC->msgarr[a], WCC->summ[a].is_new);
+                               load_calendar_item(WCC->msgarr[a], WCC->summ[a].is_new, &calv);
                        }
                        else if (is_tasks) {
                                display_task(WCC->msgarr[a], WCC->summ[a].is_new);
@@ -2947,7 +2949,7 @@ DONE:
        }
 
        if (is_calendar) {
-               do_calendar_view();     /** Render the calendar */
+               render_calendar_view(&calv);
        }
 
        if (is_addressbook) {
index ffd840853bc1470c29ac33a6093d35ada8a8a3c0..2f272e79e8d51bb89d2aa7323cda21fabaf8a465 100644 (file)
@@ -108,6 +108,7 @@ void tasks_section(void) {
 void calendar_section(void) {
        int num_msgs = 0;
        int i;
+       struct calview c;
 
        gotoroom("_CALENDAR_");
        if ( (WC->wc_view != VIEW_CALENDAR) && (WC->wc_view != VIEW_CALBRIEF) ) {
@@ -117,6 +118,8 @@ void calendar_section(void) {
                num_msgs = load_msg_ptrs("MSGS ALL", 0);
        }
 
+       parse_calendar_view_request(&c);
+
        if (num_msgs < 1) {
                wprintf("<i>");
                wprintf(_("(Nothing)"));
@@ -124,7 +127,7 @@ void calendar_section(void) {
        }
        else {
                for (i=0; i<num_msgs; ++i) {
-                       display_calendar(WC->msgarr[i], 0);
+                       load_calendar_item(WC->msgarr[i], 0, &c);
                }
                calendar_summary_view();
        }
index 265e6f0254361b8bcdf756ad2863e6544cc79715..02b7ac6a228912ed7abe495296385ad9fdbd89fd 100644 (file)
@@ -134,33 +134,33 @@ extern locale_t wc_locales[];
  *
  * bucket one...
  */
-#define QR_PERMANENT   1               /**< Room does not purge                */
-#define QR_INUSE       2               /**< Set if in use, clear if avail      */
-#define QR_PRIVATE     4               /**< Set for any type of private room   */
-#define QR_PASSWORDED  8               /**< Set if there's a password too      */
-#define QR_GUESSNAME   16              /**< Set if it's a guessname room       */
-#define QR_DIRECTORY   32              /**< Directory room                     */
-#define QR_UPLOAD      64              /**< Allowed to upload                  */
-#define QR_DOWNLOAD    128             /**< Allowed to download                */
-#define QR_VISDIR      256             /**< Visible directory                  */
-#define QR_ANONONLY    512             /**< Anonymous-Only room                */
-#define QR_ANONOPT     1024            /**< Anonymous-Option room              */
-#define QR_NETWORK     2048            /**< Shared network room                */
-#define QR_PREFONLY    4096            /**< Preferred status needed to enter   */
-#define QR_READONLY    8192            /**< Aide status required to post       */
-#define QR_MAILBOX     16384           /**< Set if this is a private mailbox   */
-
-/**
+#define QR_PERMANENT   1               /* Room does not purge          */
+#define QR_INUSE       2               /* Set if in use, clear if avail        */
+#define QR_PRIVATE     4               /* Set for any type of private room     */
+#define QR_PASSWORDED  8               /* Set if there's a password too        */
+#define QR_GUESSNAME   16              /* Set if it's a guessname room */
+#define QR_DIRECTORY   32              /* Directory room                       */
+#define QR_UPLOAD      64              /* Allowed to upload                    */
+#define QR_DOWNLOAD    128             /* Allowed to download          */
+#define QR_VISDIR      256             /* Visible directory                    */
+#define QR_ANONONLY    512             /* Anonymous-Only room          */
+#define QR_ANONOPT     1024            /* Anonymous-Option room                */
+#define QR_NETWORK     2048            /* Shared network room          */
+#define QR_PREFONLY    4096            /* Preferred status needed to enter     */
+#define QR_READONLY    8192            /* Aide status required to post */
+#define QR_MAILBOX     16384           /* Set if this is a private mailbox     */
+
+/*
  * bucket two...
  */
-#define QR2_SYSTEM     1               /**< System room; hide by default       */
-#define QR2_SELFLIST   2               /**< Self-service mailing list mgmt     */
-#define QR2_COLLABDEL  4               /**< Anyone who can post can also delete*/
-#define QR2_SUBJECTREQ  8               /**< Subject strongly recommended */
+#define QR2_SYSTEM     1               /* System room; hide by default */
+#define QR2_SELFLIST   2               /* Self-service mailing list mgmt       */
+#define QR2_COLLABDEL  4               /* Anyone who can post can also delete*/
+#define QR2_SUBJECTREQ  8               /* Subject strongly recommended */
 #define QR2_SMTP_PUBLIC 16              /* smtp public postable room */
 #define QR2_MODERATED  32              /* Listservice aide has to permit posts  */
 
-/**
+/*
  * user/room access
  */
 #define UA_KNOWN       2
@@ -169,22 +169,22 @@ extern locale_t wc_locales[];
 #define UA_ZAPPED      16
 
 
-/**
+/*
  * User flags (from Citadel)
  */
-#define US_NEEDVALID   1               /**< User needs to be validated         */
-#define US_PERM                4               /**< Permanent user                     */
-#define US_LASTOLD     16              /**< Print last old message with new    */
-#define US_EXPERT      32              /**< Experienced user                   */
-#define US_UNLISTED    64              /**< Unlisted userlog entry             */
-#define US_NOPROMPT    128             /**< Don't prompt after each message    */
-#define US_PROMPTCTL   256             /**< <N>ext & <S>top work at prompt     */
-#define US_DISAPPEAR   512             /**< Use "disappearing msg prompts"     */
-#define US_REGIS       1024            /**< Registered user                    */
-#define US_PAGINATOR   2048            /**< Pause after each screen of text    */
-#define US_INTERNET    4096            /**< Internet mail privileges           */
-#define US_FLOORS      8192            /**< User wants to see floors           */
-#define US_COLOR       16384           /**< User wants ANSI color support      */
+#define US_NEEDVALID   1               /* User needs to be validated           */
+#define US_PERM                4               /* Permanent user                       */
+#define US_LASTOLD     16              /* Print last old message with new      */
+#define US_EXPERT      32              /* Experienced user                     */
+#define US_UNLISTED    64              /* Unlisted userlog entry               */
+#define US_NOPROMPT    128             /* Don't prompt after each message      */
+#define US_PROMPTCTL   256             /* <N>ext & <S>top work at prompt       */
+#define US_DISAPPEAR   512             /* Use "disappearing msg prompts"       */
+#define US_REGIS       1024            /* Registered user                      */
+#define US_PAGINATOR   2048            /* Pause after each screen of text      */
+#define US_INTERNET    4096            /* Internet mail privileges             */
+#define US_FLOORS      8192            /* User wants to see floors             */
+#define US_COLOR       16384           /* User wants ANSI color support        */
 #define US_USER_SET    (US_LASTOLD | US_EXPERT | US_UNLISTED | \
                        US_NOPROMPT | US_DISAPPEAR | US_PAGINATOR | \
                        US_FLOORS | US_COLOR | US_PROMPTCTL )
@@ -196,16 +196,16 @@ extern locale_t wc_locales[];
 #define NLI    "(not logged in)"
 
 
-/**
+/*
  * \brief      Linked list of session variables encoded in an x-www-urlencoded content type
  */
 typedef struct urlcontent urlcontent;
 struct urlcontent {
-       char url_key[32];          /**< the variable name */
-       StrBuf *url_data;            /**< its value */
+       char url_key[32];          /* the variable name */
+       StrBuf *url_data;            /* its value */
 };
 
-/**
+/*
  * \brief information about us ???
  */ 
 struct serv_info {
@@ -230,14 +230,14 @@ struct serv_info {
 
 
 
-/**
+/*
  * \brief This struct holds a list of rooms for \\\<G\\\>oto operations.
  */
 struct march {
-       struct march *next;       /**< pointer to next in linked list */
-       char march_name[128];     /**< name of room */
-       int march_floor;          /**< floor number of room */
-       int march_order;          /**< sequence in which we are to visit this room */
+       struct march *next;       /* pointer to next in linked list */
+       char march_name[128];     /* name of room */
+       int march_floor;          /* floor number of room */
+       int march_order;          /* sequence in which we are to visit this room */
 };
 
 /* *
@@ -245,12 +245,12 @@ struct march {
  *             It is a binary tree.
  */
 struct roomlisting {
-       struct roomlisting *lnext;      /**< pointer to 'left' tree node */
-       struct roomlisting *rnext;      /**< pointer to 'right' tree node */
-       char rlname[128];               /**< name of room */
-       unsigned rlflags;               /**< room flags */
-       int rlfloor;                    /**< the floor it resides on */
-       int rlorder;                    /**< room listing order */
+       struct roomlisting *lnext;      /* pointer to 'left' tree node */
+       struct roomlisting *rnext;      /* pointer to 'right' tree node */
+       char rlname[128];               /* name of room */
+       unsigned rlflags;               /* room flags */
+       int rlfloor;                    /* the floor it resides on */
+       int rlorder;                    /* room listing order */
 };
 
 
@@ -285,16 +285,16 @@ typedef struct _TemplateToken {
 typedef void (*WCHandlerFunc)();
 
 
-/**
+/*
  * \brief Dynamic content for variable substitution in templates
  */
 typedef struct _wcsubst {
-       int wcs_type;                       /**< which type of Substitution are we */
-       char wcs_key[32];                   /**< copy of our hashkey for debugging */
-       StrBuf *wcs_value;                  /**< if we're a string, keep it here */
-       long lvalue;                        /**< type long? keep data here */
-       int ContextRequired;                /**< do we require a context type? */
-       WCHandlerFunc wcs_function; /**< funcion hook ???*/
+       int wcs_type;                       /* which type of Substitution are we */
+       char wcs_key[32];                   /* copy of our hashkey for debugging */
+       StrBuf *wcs_value;                  /* if we're a string, keep it here */
+       long lvalue;                        /* type long? keep data here */
+       int ContextRequired;                /* do we require a context type? */
+       WCHandlerFunc wcs_function; /* funcion hook ???*/
 } wcsubst;
 
 #define CTX_NONE 0
@@ -362,62 +362,62 @@ int CompareSubstToStrBuf(StrBuf *Compare, TemplateParam *ParamToLookup);
 
 
 
-/**
+/*
  * \brief Values for wcs_type
  */
 enum {
-       WCS_STRING,       /**< its a string */
-       WCS_FUNCTION,     /**< its a function callback */
-       WCS_SERVCMD,      /**< its a command to send to the citadel server */
-       WCS_STRBUF,       /**< its a strbuf we own */
-       WCS_STRBUF_REF,   /**< its a strbuf we mustn't free */
-       WCS_LONG          /**< its an integer */
+       WCS_STRING,       /* its a string */
+       WCS_FUNCTION,     /* its a function callback */
+       WCS_SERVCMD,      /* its a command to send to the citadel server */
+       WCS_STRBUF,       /* its a strbuf we own */
+       WCS_STRBUF_REF,   /* its a strbuf we mustn't free */
+       WCS_LONG          /* its an integer */
 };
 
-/**
+/*
  * \brief mail attachment ???
  */
 struct wc_attachment {
-       struct wc_attachment *next;/**< pointer to next in list */
-       size_t length;                     /**< length of the contenttype */
-       char content_type[SIZ];    /**< the content itself ???*/
-       char filename[SIZ];                /**< the filename hooked to this content ??? */
-       char *data;                /**< the data pool; aka this content */
-       long lvalue;               /**< if we put a long... */
+       struct wc_attachment *next;/* pointer to next in list */
+       size_t length;                     /* length of the contenttype */
+       char content_type[SIZ];    /* the content itself ???*/
+       char filename[SIZ];                /* the filename hooked to this content ??? */
+       char *data;                /* the data pool; aka this content */
+       long lvalue;               /* if we put a long... */
 };
 
-/**
+/*
  * \brief message summary structure. ???
  */
 struct message_summary {
-       time_t date;        /**< its creation date */
-       long msgnum;            /**< the message number on the citadel server */
-       char from[128];         /**< the author */
-       char to[128];           /**< the recipient */
-       char subj[256];         /**< the title / subject */
-       int hasattachments;     /**< does it have atachments? */
-       int is_new;         /**< is it yet read? */
+       time_t date;        /* its creation date */
+       long msgnum;            /* the message number on the citadel server */
+       char from[128];         /* the author */
+       char to[128];           /* the recipient */
+       char subj[256];         /* the title / subject */
+       int hasattachments;     /* does it have atachments? */
+       int is_new;         /* is it yet read? */
 };
 
-/**
+/*
  * \brief  Data structure for roomlist-to-folderlist conversion 
  */
 struct folder {
-       int floor;      /**< which floor is it on */
-       char room[SIZ]; /**< which roomname ??? */
-       char name[SIZ]; /**< which is its own name??? */
-       int hasnewmsgs; /**< are there unread messages inside */
-       int is_mailbox; /**< is it a mailbox?  */
-       int selectable; /**< can we select it ??? */
-       int view;       /**< whats its default view? inbox/calendar.... */
-       int num_rooms;  /**< If this is a floor, how many rooms does it have */
+       int floor;      /* which floor is it on */
+       char room[SIZ]; /* which roomname ??? */
+       char name[SIZ]; /* which is its own name??? */
+       int hasnewmsgs; /* are there unread messages inside */
+       int is_mailbox; /* is it a mailbox?  */
+       int selectable; /* can we select it ??? */
+       int view;       /* whats its default view? inbox/calendar.... */
+       int num_rooms;  /* If this is a floor, how many rooms does it have */
 };
 
 typedef struct _disp_cal {                                     
-       icalcomponent *cal;             /**< cal items for display */
-       long cal_msgnum;                /**< cal msgids for display */
-       char *from;                     /**< owner of this component */
-       int unread;                     /**< already seen by the user? */
+       icalcomponent *cal;             /* cal items for display */
+       long cal_msgnum;                /* cal msgids for display */
+       char *from;                     /* owner of this component */
+       int unread;                     /* already seen by the user? */
 
        time_t event_start;
        time_t event_end;
@@ -427,92 +427,90 @@ typedef struct _disp_cal {
 } disp_cal;                                            
 
 
-/**
- * \brief One of these is kept for each active Citadel session.
- * HTTP transactions are bound to on e at a time.
+/*
+ * One of these is kept for each active Citadel session.
+ * HTTP transactions are bound to one at a time.
  */
 struct wcsession {
-       struct wcsession *next;                 /**< Linked list */
-       int wc_session;                         /**< WebCit session ID */
-       char wc_username[128];                  /**< login name of current user */
-       char wc_fullname[128];                  /**< Screen name of current user */
-       char wc_password[128];                  /**< Password of current user */
-       char wc_roomname[256];                  /**< Room we are currently in */
-       int connected;                          /**< nonzero == we are connected to Citadel */
-       int logged_in;                          /**< nonzero == we are logged in  */
-       int axlevel;                            /**< this user's access level */
-       int is_aide;                            /**< nonzero == this user is an Aide */
-       int is_room_aide;                       /**< nonzero == this user is a Room Aide in this room */
-       int http_sock;                          /**< HTTP server socket */
-       int serv_sock;                          /**< Client socket to Citadel server */
-       int chat_sock;                          /**< Client socket to Citadel server - for chat */
-       unsigned room_flags;                    /**< flags associated with the current room */
-       unsigned room_flags2;                   /**< flags associated with the current room */
-       int wc_view;                            /**< view for the current room */
-       int wc_default_view;                    /**< default view for the current room */
-       int wc_is_trash;                        /**< nonzero == current room is a Trash folder */
-       int wc_floor;                           /**< floor number of current room */
-       char ugname[128];                       /**< where does 'ungoto' take us */
-       long uglsn;                             /**< last seen message number for ungoto */
-       int upload_length;                      /**< content length of http-uploaded data */
-       char *upload;                           /**< pointer to http-uploaded data */
-       char upload_filename[PATH_MAX];         /**< filename of http-uploaded data */
-       char upload_content_type[256];          /**< content type of http-uploaded data */
-       int new_mail;                           /**< user has new mail waiting */
-       int remember_new_mail;                  /**< last count of new mail messages */
-       int need_regi;                          /**< This user needs to register. */
-       int need_vali;                          /**< New users require validation. */
-       char cs_inet_email[256];                /**< User's preferred Internet addr. */
-       pthread_mutex_t SessionMutex;           /**< mutex for exclusive access */
-       time_t lastreq;                         /**< Timestamp of most recent HTTP */
-       int killthis;                           /**< Nonzero == purge this session */
-       struct march *march;                    /**< march mode room list */
-       char reply_to[512];                     /**< reply-to address */
-       long msgarr[10000];                     /**< for read operations */
-       int num_summ;                           /**< number of messages in mailbox summary view */
-       struct message_summary *summ;           /**< array of messages for mailbox summary view */
-       int is_mobile;                  /**< Client is a handheld browser */
-       HashList *urlstrings;                   /**< variables passed to webcit in a URL */
-       HashList *vars;                         /**< HTTP variable substitutions for this page */
-       char this_page[512];                    /**< URL of current page */
-       char http_host[512];                    /**< HTTP Host: header */
-       HashList *hash_prefs;                   /**< WebCit preferences for this user */
-       HashList *disp_cal_items;               /**< sorted list of calendar items; startdate is the sort criteria. */
-       struct wc_attachment *first_attachment; /**< linked list of attachments for 'enter message' */
-       char last_chat_user[256];               /**< ??? todo */
-       char ImportantMessage[SIZ];             /**< ??? todo */
-       int ctdl_pid;                           /**< Session ID on the Citadel server */
-       char httpauth_user[256];                /**< only for GroupDAV sessions */
-       char httpauth_pass[256];                /**< only for GroupDAV sessions */
-       int gzip_ok;                            /**< Nonzero if Accept-encoding: gzip */
-       int is_mailbox;                         /**< the current room is a private mailbox */
-       struct folder *cache_fold;              /**< cache the iconbar room list */
-       int cache_max_folders;                  /**< ??? todo */
-       int cache_num_floors;                   /**< ??? todo */
-       time_t cache_timestamp;                 /**< ??? todo */
-       HashList *IconBarSetttings;             /**< which icons should be shown / not shown? */
-       long current_iconbar;                   /**< What is currently in the iconbar? */
-       const StrBuf *floordiv_expanded;        /**< which floordiv currently expanded */
-       int selected_language;                  /**< Language selected by user */
-       time_t last_pager_check;                /**< last time we polled for instant msgs */
-       int nonce;                              /**< session nonce (to prevent session riding) */
-       int time_format_cache;                  /**< which timeformat does our user like? */
-       StrBuf *UrlFragment1;                   /**< first urlfragment, if NEED_URL is specified by the handler*/
-       StrBuf *UrlFragment2;                   /**< second urlfragment, if NEED_URL is specified by the handler*/
-       StrBuf *WBuf;                           /**< Our output buffer */
-       StrBuf *HBuf;                           /**< Our HeaderBuffer */
-       StrBuf *CLineBuf;                       /**< linebuffering client stuff */
-
-       HashList *ServCfg;                      /**< cache our server config for editing */
-       HashList *InetCfg;                      /**< Our inet server config for editing */
-
-       StrBuf *trailing_javascript;            /**< extra javascript to be appended to page */
+       struct wcsession *next;                 /* Linked list */
+       int wc_session;                         /* WebCit session ID */
+       char wc_username[128];                  /* login name of current user */
+       char wc_fullname[128];                  /* Screen name of current user */
+       char wc_password[128];                  /* Password of current user */
+       char wc_roomname[256];                  /* Room we are currently in */
+       int connected;                          /* nonzero == we are connected to Citadel */
+       int logged_in;                          /* nonzero == we are logged in  */
+       int axlevel;                            /* this user's access level */
+       int is_aide;                            /* nonzero == this user is an Aide */
+       int is_room_aide;                       /* nonzero == this user is a Room Aide in this room */
+       int http_sock;                          /* HTTP server socket */
+       int serv_sock;                          /* Client socket to Citadel server */
+       int chat_sock;                          /* Client socket to Citadel server - for chat */
+       unsigned room_flags;                    /* flags associated with the current room */
+       unsigned room_flags2;                   /* flags associated with the current room */
+       int wc_view;                            /* view for the current room */
+       int wc_default_view;                    /* default view for the current room */
+       int wc_is_trash;                        /* nonzero == current room is a Trash folder */
+       int wc_floor;                           /* floor number of current room */
+       char ugname[128];                       /* where does 'ungoto' take us */
+       long uglsn;                             /* last seen message number for ungoto */
+       int upload_length;                      /* content length of http-uploaded data */
+       char *upload;                           /* pointer to http-uploaded data */
+       char upload_filename[PATH_MAX];         /* filename of http-uploaded data */
+       char upload_content_type[256];          /* content type of http-uploaded data */
+       int new_mail;                           /* user has new mail waiting */
+       int remember_new_mail;                  /* last count of new mail messages */
+       int need_regi;                          /* This user needs to register. */
+       int need_vali;                          /* New users require validation. */
+       char cs_inet_email[256];                /* User's preferred Internet addr. */
+       pthread_mutex_t SessionMutex;           /* mutex for exclusive access */
+       time_t lastreq;                         /* Timestamp of most recent HTTP */
+       int killthis;                           /* Nonzero == purge this session */
+       struct march *march;                    /* march mode room list */
+       char reply_to[512];                     /* reply-to address */
+       long msgarr[10000];                     /* for read operations */
+       int num_summ;                           /* number of messages in mailbox summary view */
+       struct message_summary *summ;           /* array of messages for mailbox summary view */
+       int is_mobile;                          /* Client is a handheld browser */
+       HashList *urlstrings;                   /* variables passed to webcit in a URL */
+       HashList *vars;                         /* HTTP variable substitutions for this page */
+       char this_page[512];                    /* URL of current page */
+       char http_host[512];                    /* HTTP Host: header */
+       HashList *hash_prefs;                   /* WebCit preferences for this user */
+       HashList *disp_cal_items;               /* sorted list of calendar items; startdate is the sort criteria. */
+       struct wc_attachment *first_attachment; /* linked list of attachments for 'enter message' */
+       char last_chat_user[256];
+       char ImportantMessage[SIZ];
+       int ctdl_pid;                           /* Session ID on the Citadel server */
+       char httpauth_user[256];                /* only for GroupDAV sessions */
+       char httpauth_pass[256];                /* only for GroupDAV sessions */
+       int gzip_ok;                            /* Nonzero if Accept-encoding: gzip */
+       int is_mailbox;                         /* the current room is a private mailbox */
+       struct folder *cache_fold;              /* cache the iconbar room list */
+       int cache_max_folders;
+       int cache_num_floors;
+       time_t cache_timestamp;
+       HashList *IconBarSetttings;             /* which icons should be shown / not shown? */
+       long current_iconbar;                   /* What is currently in the iconbar? */
+       const StrBuf *floordiv_expanded;        /* which floordiv currently expanded */
+       int selected_language;                  /* Language selected by user */
+       time_t last_pager_check;                /* last time we polled for instant msgs */
+       int nonce;                              /* session nonce (to prevent session riding) */
+       int time_format_cache;                  /* which timeformat does our user like? */
+       StrBuf *UrlFragment1;                   /* first urlfragment, if NEED_URL is specified by handler*/
+       StrBuf *UrlFragment2;                   /* second urlfragment, if NEED_URL is specified by handler*/
+       StrBuf *WBuf;                           /* Our output buffer */
+       StrBuf *HBuf;                           /* Our HeaderBuffer */
+       StrBuf *CLineBuf;                       /* linebuffering client stuff */
+       HashList *ServCfg;                      /* cache our server config for editing */
+       HashList *InetCfg;                      /* Our inet server config for editing */
+       StrBuf *trailing_javascript;            /* extra javascript to be appended to page */
 };
 
-/** values for WC->current_iconbar */
+/* values for WC->current_iconbar */
 enum {
-       current_iconbar_menu,     /**< view the icon menue */
-       current_iconbar_roomlist  /**< view the roomtree */
+       current_iconbar_menu,     /* view the icon menue */
+       current_iconbar_roomlist  /* view the roomtree */
 };
 enum {
        S_SELECT,
@@ -520,6 +518,27 @@ enum {
        MAX_SEMAPHORES
 };
 
+
+/*
+ * calview contains data passed back and forth between the message fetching loop
+ * and the calendar view renderer.
+ */
+enum {
+       calview_month,
+       calview_day,
+       calview_week,
+       calview_brief
+};
+
+struct calview {
+       int view;
+       int year;
+       int month;
+       int day;
+       time_t lower_bound;
+       time_t upper_bound;
+};
+
 #ifndef num_parms
 #define num_parms(source)              num_tokens(source, '|') 
 #endif
@@ -749,11 +768,12 @@ void do_listsub(void);
 void toggle_self_service(void);
 ssize_t write(int fd, const void *buf, size_t count);
 void cal_process_attachment(char *part_source, long msgnum, char *cal_partnum);
-void display_calendar(long msgnum, int unread);
+void load_calendar_item(long msgnum, int unread, struct calview *c);
 void display_task(long msgnum, int unread);
 void display_note(long msgnum, int unread);
 void updatenote(void);
-void do_calendar_view(void);
+void parse_calendar_view_request(struct calview *c);
+void render_calendar_view(struct calview *c);
 void do_tasks_view(void);
 void calendar_summary_view(void);
 int load_msg_ptrs(char *servcmd, int with_headers);
@@ -777,8 +797,10 @@ icaltimezone *get_default_icaltimezone(void);
 void display_icaltimetype_as_webform(struct icaltimetype *, char *, int);
 void icaltime_from_webform(struct icaltimetype *result, char *prefix);
 void icaltime_from_webform_dateonly(struct icaltimetype *result, char *prefix);
-void display_edit_individual_event(icalcomponent *supplied_vtodo, long msgnum, char *from, int unread);
-void save_individual_event(icalcomponent *supplied_vtodo, long msgnum, char *from, int unread);
+void display_edit_individual_event(icalcomponent *supplied_vtodo, long msgnum, char *from,
+       int unread, struct calview *calv);
+void save_individual_event(icalcomponent *supplied_vtodo, long msgnum, char *from,
+       int unread, struct calview *calv);
 void ical_dezonify(icalcomponent *cal);
 void partstat_as_string(char *buf, icalproperty *attendee);
 icalcomponent *ical_encapsulate_subcomponent(icalcomponent *subcomp);
@@ -866,7 +888,7 @@ void utf8ify_rfc822_string(char *buf);
 void begin_burst(void);
 long end_burst(void);
 
-extern char *hourname[];       /**< Names of hours (12am, 1am, etc.) */
+extern char *hourname[];       /* Names of hours (12am, 1am, etc.) */
 
 void http_datestring(char *buf, size_t n, time_t xtime);