At the Forge - Dynamically Generated Calendars
The real solution, and one that makes life more interesting, is to create the iCalendar file dynamically when the user requests it. That is, our CGI program does not return the contents of an existing iCalendar file; instead, it creates an iCalendar file programmatically, returning it to the user's calendar client program.
At first glance, this might seem to be a simple task. After all, the iCalendar file format appears to be straightforward, so maybe we can code something together ourselves. But upon closer examination, we discover that creating an iCalendar file is easier said than done, particularly if we want to include recurring events.
Given the increasing popularity of the iCalendar standard and the plethora of open-source projects, I was surprised to discover the relative lack of attention that iCalendar has received from the biggest open-source programming communities. Part of my surprise was because iCalendar has been around for several years, is used by many companies and is supported by many calendar programs, from Novell's Evolution to Lotus Notes to Microsoft Outlook. This combination usually is a recipe for several different options, in several different programming languages.
I first looked at Perl, whose CPAN archive is renowned for its many modules, including many for Internet standards of various sorts. Although several Perl modules are available that parse iCalendar files, no up-to-date module exists for building them. Net::ICal::Libical was going to be a wrapper around the C-language libical library but was last released in a pre-alpha version, several years ago. Net::ICal was part of a project called ReefKnot, which also appears to have been abandoned.
Luckily, the Danish developer Max M (see the on-line Resources) recently decided to fill this gap and wrote a Python package that makes it easy to create an iCalendar file. I downloaded and installed the package on my computer without any trouble, and I found that it is quite straightforward to create a calendar with this package. Combined with our simple CGI program from before, we should be able to create and publish a calendar without any trouble.
I downloaded and installed the iCalendar package from the maxm.dk site. Unlike many modern Python packages, it doesn't install automatically. You must copy it manually to your system's site-packages directory, which on my Fedora Core 3 system is located at /usr/lib/python-2.3/site-packages.
As you can see in Listing 2, I was able to use this newly installed iCalendar package to create new objects of type Calendar and Event. The first thing I had to do was import the appropriate packages into the current namespace:
from iCalendar import Calendar, Event
Listing 2. dynamic-calendar.py, a program that generates a calendar in iCalendar format.
#!/usr/bin/python
# Grab the CGI module
import cgi
from iCalendar import Calendar, Event
from datetime import datetime
from iCalendar import UTC # timezone
# Log any problems that we might have
import cgitb
cgitb.enable(display=0, logdir="/tmp")
# Send a content-type header to the user's browser
print "Content-type: text/calendar\n\n"
# Create a calendar object
cal = Calendar()
# What product created the calendar?
cal.add('prodid',
'-//Python iCalendar 0.9.3//mxm.dk//')
# Version 2.0 corresponds to RFC 2445
cal.add('version', '2.0')
# Create one event
event = Event()
event.add('summary', 'ATF deadline')
event.add('dtstart',
datetime(2005,3,11,8,0,0,tzinfo=UTC()))
event.add('dtend',
datetime(2005,3,11,10,0,0,tzinfo=UTC()))
event.add('dtstamp',
datetime(2005,3,11,0,10,0,tzinfo=UTC()))
event['uid'] = 'ATF20050311A@lerner.co.il'
# Give this very high priority!
event.add('priority', 5)
# Add the event to the calendar
cal.add_component(event)
# Ask the calendar to render itself as an iCalendar
# file, and return that file in an HTTP response!
print cal.as_string()
The Calendar and Event modules inside of the iCalendar package correspond to the entire iCalendar file and one event in that file, respectively. We thus create a single instance of the Calendar object and one Event object for each event that we might want to create.
We then can create the calendar object:
cal = Calendar()
cal.add('prodid',
'-//Python iCalendar 0.9.3//mxm.dk//')
cal.add('version', '2.0')
The second and third lines here, in which we invoke cal.add(), allow us to add identifying data to our iCalendar file. The first of these allows us to tell the client software which program generated the iCalendar file. This is useful for debugging; if we consistently get corrupt iCalendar files from a particular software package, we can contact the author or publisher and report a bug. The second line, in which we add a version identifier, indicates which version of the iCalendar specification we are following. RFC 2445 indicates that we should give this field a value of 2.0 if we are going to follow that specification.
Now that we have created a calendar, let's create an event and give it a summary line to be displayed in the calendar program of anyone subscribing to this iCalendar file:
event = Event()
event.add('summary', 'ATF deadline')
Every event, as we have already seen in the file we examined, has three date/time fields associated with it: the starting date and time, dtstart; the ending date and time, dtend; and an indication of when this entry was added to the calendar, dtstamp. The iCalendar standard uses a strange if useful format for its dates and times, but the Event object knows how to work with those if we give it a datetime object from the standard datetime Python package. So, we can say:
event.add('dtstart',
datetime(2005,3,11,14,0,0,tzinfo=UTC()))
event.add('dtend',
datetime(2005,3,11,16,0,0,tzinfo=UTC()))
event.add('dtstamp',
datetime(2005,3,11,0,10,0,tzinfo=UTC()))
Notice that the above three lines used UTC as the time zone. When the iCalendar file is displayed inside of a client Calendar application, it is shown with the user's local time zone, as opposed to UTC.
Once we have created the event, we need to give it a unique ID. When I say unique, I mean that the ID should be truly unique, across all calendars and computers in the world. This sounds trickier than it actually is. You can use a number of different strategies, including using a combination of the creation timestamp, IP address of the computer on which the event was created and a large random number. I decided to create a simple UID, but if you are creating an application to be shared across multiple computers, you probably should think about what sort of UIDs you want to create and then standardize on them:
event['uid'] = 'ATF20050311A@lerner.co.il'
Finally, we must give our event a priority, in the range of 0 through 9. An event with priority 5 is considered to be normal or average; urgent items get higher numbers and less-urgent items get lower ones:
event.add('priority', 5)
Once we have created our event, we attach it to the calendar object, which has been waiting for us to do something with it:
cal.add_component(event)
If we are so interested, we then could to add more events to the calendar. So long as each has a unique UID field, there won't be any problems.
Finally, we turn our Calendar object into an iCalendar file, using the as_string() method:
print cal.as_string()
Because print writes to standard output by default, and because CGI programs send their standard output back to the HTTP client, this has the effect of sending an iCalendar file back to whoever made the HTTP request. And because we have defined the MIME type to be of type text/calendar, the HTTP client knows to interpret this as a calendar and display it appropriately. If we look at the output ourselves, we see that it is indeed in iCalendar format:
BEGIN:VCALENDAR PRODID:-//Python iCalendar 0.9.3//mxm.dk// VERSION:2.0 BEGIN:VEVENT DTEND:20050311T160000Z DTSTAMP:20050311T001000Z DTSTART:20050311T140000Z PRIORITY:5 SUMMARY:ATF deadline UID:ATF20050311A@lerner.co.il END:VEVENT END:VCALENDAR
Now, I must admit that this example is almost as contrived as the previous one. True, we have exploited the fact that we can generate a calendar dynamically, but this event was hard-coded into the program, making it impossible for a nonprogrammer to add, modify or delete the event. That said, we have taken an additional step toward the programmatic calculation of events and dates. The next step is to store the dates in a file or even in a relational database and to use our program to convert the information on the fly.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- Designing Electronics with Linux
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Dynamic DNS—an Object Lesson in Problem Solving
- Linux Systems Administrator
- Senior Perl Developer
- Technical Support Rep
- UX Designer
- Web & UI Developer (JavaScript & j Query)
- Using Salt Stack and Vagrant for Drupal Development
- Reply to comment | Linux Journal
1 hour 38 min ago - Dynamic DNS
2 hours 12 min ago - Reply to comment | Linux Journal
3 hours 10 min ago - Reply to comment | Linux Journal
4 hours 1 min ago - Not free anymore
8 hours 2 min ago - Great
11 hours 50 min ago - Reply to comment | Linux Journal
11 hours 58 min ago - Understanding the Linux Kernel
14 hours 12 min ago - General
16 hours 42 min ago - Kernel Problem
1 day 2 hours ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?




Comments
The webpage for this module s
The webpage for this module seems to have been moved to http://codespeak.net/icalendar/ where there are much more current releases available than reviewed here. Amongst other things, it now supports installation via the command "python setup.py install"
The old webpage still exists and makes no acknowledgement of the new site, thus I understand the author's confusion.
iCalendar/vCalendar
I really liked the article, and I like where it's going. I'm a member of more than one non-profit org that would benefit greatly from a calendar system like the one proposed.
Unfortunately, MS Outlook, the calendar used by most of the members, does not seem to like iCalendar files generated by Mozilla. I don't know if MSO's iCalendar/vCalendar import works at all.
On MSO 2000, it just says it can't read the file. On MSO 2003, it displays the message
"This error can appear if you have attempted to save a recurring Lunar appointment in iCalendar format.
To avoid this error, set the appointment option to Gregorian instead of Lunar."
So I tried a file that had only 2 appointments, both non-recurring. Still got the same message. Configuring Mozilla to store universal time didn't help either.
MSO will not export an .ics/.vcs file, so it's difficult to see what it thinks is a good example.
I think this problem will somehow have to be resolved to make this idea really useful, since unfortunately I can't dictate to the other members what calendar app they should use. Any ideas?
Thanks,
--Jeff in Austin, TX
MSO exports icalendar files j
MSO exports icalendar files just fine. Just send an appointment using internet format or drag and drop an appointment on an email after setting the default format to iCalendar. Then you can examine the format of a MSO iCalendar file.