TODO SOONER: Integrate the Exchange2Ical code into the subscription code to pull from Exchange servers. Replace the log() call with log4j. Add a location field to events. Change the "guest user" system to not use (or at least not display) a real account. Instead, add a "guest settings" button to allow a theme and permission level to be chosen. Add a flag to force the user to change their password on the next login. Allow sub-events to be entered. For example, a meeting might take place from 7-9 PM, but within that time, 30 minutes might go to activity A and the next 30 minutes might go to activity B. If the activities are not entered as separate events, it will be easier to integrate the attendance system to use the same events as the calendar. This is actually just a data entry and formatting issue with the description. Allow contributions from the frontend that are to be reviewed by the admin Allow recurrences to have exceptions/arbitrary dates Extend the database structure to allow multiple calendars per site Implement per-calendar (per-category?) permissions TODO LATER: Check the tab order on all input screens. Change the "start" and "end" boxes to use little mini-calendars to select dates. Change the event admin interface to do contextual editing on the grid. Change the "forgot my password" system to instead send a link to a "change your password" page. Convert the passwords to encrypted hashes (use MySQL's PASSWORD function). Change the recurrence data model to follow the iCalendar RRULE model. Extend the series edit screen to allow a series to occur on the nth weekday or weekend. Extend the series edit screen to handle very strange occurrances like election day -- the first Tuesday after the first Monday in November every 4 years. Consider adding an "expert" flag to hide the helpful text. Consider converting the interface to use XHTML instead of HTML Consider re-implementing the export to outlook and palm Provide invitations Provide reminders (would this require a public signup system?) Provide an iCal/Sunbird WEBDAV import -- dynamic WEBDAV in Java is not easy. Clean up the admin tool help text and move them to separate pages. Come up with a way to set a minimum width on a stretchable table. CLEANUP: Add a date formatting class that will override SimpleDateFormat, hide the format strings and correctly handle empty dates. CLEANUP: Move some of the text formatting code out of CalendarHelper into classes in the servlet folder. VERSION 3.7.0 - 4/12/2006 Changed the user edit screen to show the "No access" option for the type. Updated the copyright statement at the top of each file to 2006. Fixed several small errors in the INSTALL.txt file and removed the instruction to edit the calendar.sql file. Added the calendar_subscription table, the calendar_theme_subscription table and the subscription_id field to the calendar_event table to track webcal subscriptions and the imported events. Added getSubscription() to Event.java. Added the Subscription class. Added get/setSubscriptions to the Theme class. Added the subscription admin/edit interfaces to the admin tool. Created RefreshSubscriptions to run as a thread and update subscriptions periodically (interval set per subscription). The thread checks to see if updates are needed on an interval read from the calendar.properties file. Changed the ical.vm template to specify DATE-TIME values instead of just DATE values (where appropriate). Added the copyright/license statement to the top of the ical.vm file. Finished adding the double-submit protection to AdminServlet -- for some reason, it wasn't in the delete code. Attempting to delete the same object twice technically won't hurt anything because the second attempt will return an error but the error message might confuse the user who doesn't understand that they just refreshed the page. Changed Initialize to start the DumpCache thread instead of making DumpCache a servlet started from the web.config. The dump interval is now read from the calendar.properties file instead of web.config. Fixed a bug in CalendarHelper.addDuration() that was miscalculating end dates when the event spanned the start or end of daylight savings time. This was only affecting recurring events. Added CalendarHelper.canonicalizeIcal() to correctly encode values for iCalendar, according to RFC 2445. Changed iCalendarServlet to use basic authentication instead of passing the user ID in the parameter string. Changed all of the logging statements to use a central logging facility in Helper so the log level can be controlled. Added a log_level variable to calendar.properties to control the verbosity of the logging. Added get/setUnsavable() to Occurrence to prevent temporary Occurrence objects from being saved for any reason. Added get/setUnsavable() to Event to prevent temporary Event objects from being saved for any reason. Fixed an obscure display problem in grid.vm that would cause a multi-day event displayed after but on the same row as an all-day event to occupy one additional day before it should. Added Event.combineFreeBusy() to combine events in a list that occur at the same time or overlap and replace their events with "Busy". Added a new User type: CALENDAR_TYPE_FLAG_VIEW_FREEBUSY that can only see the calendar grid as a series of "Busy" blocks with no details. Fixed a minor bug in the webcal link on the calendar grid -- immediately after logging out, the link would still contain the authorization parameter for the login. VERSION 3.6.0 -- 3/27/2006 Removed the initialization parameters from the web.xml file and created a calendar.properties file that contains those values instead. This makes it much easier to access those values within the classes without passing a bunch of values up from the calling servlet. Added an Initialize class that will load on startup to load the Velocity and calendar properties files. Because Velocity is a singleton, initializing it once is enough. Removed the loadConfiguration() function from AdminServlet, CalendarServlet and iCalendarServlet, since Initialize is now doing that work. Moved the Velocity-specific classes from the servlet package into their own velocity package. Updated the INSTALL.txt file to contain instructions to update the properties file instead of the web.xml file. Added an UPGRADING.txt to provide upgrading instructions for users who aren't developers of this package. Moved the email-sending code from CalendarUser to CalendarHelper to make it more easily reusable. Renamed CalendarUser.sendReminderEmail() to sendPasswordReminderEmail(), changed it to call CalendarHelper.sendEmail() and to use a Velocity template for its email content. Changed the procedure for preventing multiple submissions to include a hidden field with a unique value. The value is saved after a new record is created and compared with the next submission. If the values match, the save is not carried out. Fixed the ical.vm template to produce a valid vCalendar file, importable by Apple's iCal. Changed iCalendarServlet to only show categories from a user's theme, unless a theme_id parameter is passed in. Changed the webcal link to pass on the theme ID. Changed the way categories are selected when an event is saved. Before, saving an event automatically selected its categories when the event list appeared. Now, both the previously-selected categories and the saved event's categories are selected. Fixed a minor display problem where clicking "New event", then "Cancel" would open the current month and year, not the previously selected month and year. VERSION 3.5.1 -- 10/26/2005 Fixed Event.loadOccurrences() to correctly eliminate duplicates by checking both the IDs and the dates. This is necessary because Recurrence.load() returns an Occurrence[] full of objects with the same IDs but different dates. When those objects were placed in consecutive positions, Event.loadOccurrences() was deleting them. Hopefully this will be the last time this bug comes up but that's unlikely -- apparently there are an infinite number of ways to screw this up. VERSION 3.5.0 -- 10/26/2005 Fixed the profile setting "Always use default theme". It was actually saving the currently-default theme as the user's selection instead of a special value to signify that the default theme should be found each time. Fixed Event.loadOccurrences() to explicitly eliminate duplicates from the returned array. This is necessary because the parameters may indicate to only pull occurrences from specific categories and an event may exist in multiple categories. Changed CalendarHelper.getDatabaseConnection() and CalendarHelper.putDatabaseConnection() to be non-static. Added an interface named Helper that defines get/putDatabaseConnection() and changed CalendarHelper to implement it. Changed all internal uses of CalendarHelper to use an instance of Helper instead of calling static functions on CalendarHelper. This required changing all the constructors to accept a Helper parameter, all instantiations to pass along the Helper variable and most static functions to accept a Helper parameter. Changed all compareTo() functions to use "target_object instanceof CLASS" instead of "this.getClass().equals(target_object.getClass())". Fixed DumpCache.run() to actually run more than once using a while() loop, instead of just running once and exiting. Renamed the User class to CalendarUser. Added an interface named User that defines all of the public methods and changed CalendarUser to implement it. The biggest change this forces is that load() and friends are no longer static. Removed all of the reflection code from the servlet classes to find and use the User class and changed them to call the User interface instead. This simplifies the code quite a bit. Removed a number of wrapper functions from CalendarUser that were only present to provide an object parameter instead of a basic data type. Now that the class isn't being used through reflection, the wrappers aren't needed any more. Changed all of the classes to use a centralized, overridable caching system. This allows caches that index on more than just the database sort order. Fixed the calendar grid to display the month/year selector to mobile devices. Removed split() and replace() from CalendarHelper and changed all their references to use String.split() and String.replaceAll() instead. Added checks to all classes to ensure that getDatabaseConnection() returns a non-null value. Closed a small security hole in AdminServlet where a cleverly crafted request from an unauthorized user could have revealed the email addresses and names of all the users in the database. Moved the static strings from CalendarHelper to Helper. Added a check to display an error message if the current site is not valid. When the calendar system runs standalone, the error should never be displayed. Added the JAR files for Jakarta Commons Collections, Log4J and MySQL Connector/J to the WEB-INF/lib directory. To comply with the Apache license, the Apache license and a NOTES file were added to the documentation folder. Corrected the INSTALL.TXT file to remove download instructions for the included packages and indicate that the JavaMail API and JavaBeans Activation Framework need to be downloaded and installed. Removed the text "Portions Copyright (C)2004 lookandfeel new media" from each java file, since the only lookandfeel code is in the com.lookandfeel.guid.jar file. Changed the copyright notice at the top of each file to specify that the code is only available under the GNU GPL version 2. Changed the value of the "form_action" context variable to come from an init parameter instead of being hardcoded to "calendar_admin". Fixed a minor thinko in the logout code that would always redirect the user to the login form after logging out, instead of showing them the calendar if the anonymous user can see it. Changed all save and delete actions in the admin tool to use a redirect page so refreshing the "Saved!" and "Deleted!" messages won't try to repeat the action. VERSION 3.4.2 -- 8/15/2005 Changed the names of the leakytent packages referenced through reflection. This only affects the calendar code if it is running as part of the leakytent system. Moved the version.txt file into templates/calendar and provided a soft link to it in the website root. Fixed a subtle problem in Event.loadOccurrences() that would treat a null entry in the given event array as a null event array, thus loading all occurrences of all events instead of just skipping it. This was giving a lot of strange duplications in production. VERSION 3.4.1 -- 6/7/2005 Moved the GUID generation code into a JAR file. Changed the values of the user type flags (again) to make "NONE" a non-zero value. Renamed calendar_admin_user_admin.vm to admin_user_admin.vm, calendar_admin_user_edit.vm to admin_user_edit.vm, calendar_admin_main_menu.vm to main_menu.vm. Unified calendar_admin_login.vm and calendar_login.vm into just login.vm. Changed AdminServlet to use the new template names. Changed the URL of the admin tool to "calendar_admin" instead of just "admin". Changed the name of the velocity variable for CalendarHelper to just "helper". Renamed the "calendar_category" table to just "category". Added the "compute_percentages" and "highlight_percentages" fields to the "category" table and changed the Category class to load and save them. Renamed the "calendar_admin_category_admin.vm" and "calendar_admin_category_edit.vm" templates to "admin_category_admin.vm" and "admin_category_edit.vm". Moved all of the "calendar_"-prefixed templates into a folder named "calendar" and removed the prefixes. Fixed a typo in AdminServlet that was preventing the series edit screen from correctly loading the categories a series belongs to. Added a feature that will automatically create an admin login if no users exist in the database. The login will have the email address "admin@example.com" and the password "admin". Added a feature to force the user to change the default admin login's email address and/or password. This also prevents the admin from setting a user's email address and password to match the default settings. Fixed a bug in CalendarServlet that would throw an error if the user was logged in as a user that had been deleted. Added a version.txt file to indicate what version is installed. VERSION 3.4.0 -- 5/30/2005 Added an "edit profile" button to the main menu to allow non-admin users to change their passwords and update their profiles. Added a check to User.setEmailAddress() to ensure the new email address is unique. Fixed a minor display problem on the category admin screen. Changed the calendar grid to display the event name in the summary section if no description is available. Added some helpful text to the admin tool edit screens. Fixed a small oversight in AdminServlet.java -- macintosh_agent was being set but never exported to Velocity. Renamed all of the admin tool templates to use a "calendar_" prefix. Changed the version number to use three digits instead of four. Changed the user types to use maskable integer values instead of just integers. That should make it easier to integrate with the attendance system. Fixed a bug in AdminServlet.getEventList() that might try to sort the ArrayList when it contains null objects. This was causing Event.compareTo() to throw a ClassCastException. Renamed all of the database tables except "user" to use a prefix of "calendar_" to make integration with the attendance system easier. Changed all of the servlets to use reflection to find the User class so they can use the com.leakytent package if it is available. Otherwise, they will fall back to the local User class. VERSION 3.3.0.0 -- 5/4/2005 Fixed a small bug in admin_theme_edit.vm that wasn't canonicalizing the pre and post include text correctly for a TEXTAREA. Changed the way the theme preview displays so it will use an including document with the proper body tag instead of just showing the grid itself. The difference is noticable when the theme specifies a non-white background. Fixed a bug that didn't associate the themed widths with the correct columns if the first day of the week wasn't Sunday. Changed CalendarHelper.getDuration() to only calculate weeks, days, hours, minutes and seconds -- not to also calculate years and months. Trying to find a good way to say a duration lasts a specific number of months is problematic since all months aren't the same length. In any case, there's not much need to describe events in terms of the months they last, since an entire month is a very unusual amount of time for an event to last. Changed CalendarHelper.addDuration() and Occurrence.getDuration() to understand the changes to CalendarHelper.getDuration(). Fixed CalendarServlet to display events on all of the visible days, not just the days in the current month. Fixed a big problem with Recurrence.load() that was incorrectly calculating recurring dates that either spanned the given period of time or had start dates that were after the first potential occurrence date within the given dates. Fixed a problem with Event.loadOccurrences that was causing all of the occurrences except those from the last event to be lost when an array of events is given. Added categories to themes. Now, a theme is associated with a list of categories. When the theme is selected, it displays only the events from its associated categories. Added categories to the event admin display. It is now possible to display only the events from specific categories in the admin tool. Checked every place user-entered data is output to make sure it is being correctly canonicalized. Removed the old JSP implementation (since it didn't work anyway). Fixed Category.getEvents() to remove duplicates. Fixed a calendar grid display problem that wasn't correctly displaying a multi-day event on the same row as an all day event -- it was showing the multi-day event starting one day too early. VERSION 3.2.0.0 -- 4/18/2005 Removed a change from 3.1.0.0 that attempted to get rid of the index.jsp file that redirected to the calendar servlet. It turns out that if you put a URL mapping to a servlet from "/", Tomcat will send every request to the site to your servlet, including requests for static files. Removed the MySQL and Log4J JAR files from the WEB-INF/lib folder and updated the INSTALL.txt document to tell the user where to find them. VERSION 3.1.0.0 -- 4/15/2005 Fixed a syntax problem in the web.xml file so Tomcat will actually start the application. Updated INSTALL.txt to provide a hint that the admin should customize the web.xml file. Added a "Forgot my password" button to the login screens to email the password to the user. Added a custom logger for Velocity to throw away all of its (voluminous) log messages. Added an iCalendar feed to allow Apple iCal and Mozilla Sunbird users to subscribe to the calendar. VERSION 3.0.0.0 -- 4/14/2005 Completely reimplemented in Java. All functionality from the ASP version is present except the Outlook/Palm export feature and the ability to turn off categories from the frontend. Most importantly, this version now uses Tomcat and MySQL instead of IIS and SQL Server. The admin tool and frontend also support authentication, unlike the ASP version which had no password protection at all.