Chapter 15. Accessing Online Calendars and?Event Aggregators

Table of Contents

Google Calendar
Setting Up Google Calendar As an End User
Exploring the Feed Formats from Google Calendar
Using the ­GData-­Based Calendar API Directly
Using the PHP API Kit for Google Calendar
Using the Python API Kit for Google Calendar
30boxes.com
An End User Tutorial
30boxes.com API
Event Aggregators
Upcoming.yahoo.com
Eventful.com
Programming with iCalendar
Python and iCalendar
PHP and iCalendar
Exporting an Events Calendar to iCalendar and Google Calendar
The Source: UC Berkeley Event Calendars
Creating an iCalendar Feed of Critic’s Choice Using Python
Writing the Events to Google Calendar
Summary

Online calendars will move from being merely trendy to virtually indispensable as our lives move increasingly to the network. Calendaring (scheduling appointments and coordinating calendars) is something most of us can relate to since we all have appointments that we make and keep.

As we use electronic calendars, there is a good chance that we will have more than one calendar to synchronize—people use different calendars or work with people with other calendars, no matter how much Microsoft, Apple, Google, or Yahoo! might want everyone to use its calendar alone. A lot of this calendaring activity has moved to not only digital form but specifically to a networked digital form. In addition to the old calendars, new generations of online calendars are coming into existence—that’s the focus of this chapter.

Online calendars exist in the context of other digital calendars: desktop calendars such as Microsoft Outlook and Apple iCal and calendars on handheld devices such as the Palm calendar. Much work has been done on synchronizing these calendars. Of course, calendar synchronization has been operant for a while, but these approaches (specialized conduits/SyncML[230][231]

In addition to the proliferation of online calendars, event aggregation sites such as Upcoming.yahoo.com and Eventful.com are starting to create a marketplace of event data. They are focused on public events, whereas online calendars have as their focal point individuals and private events. These worlds intersect, of course, because individual users often track the public events they attend on their individual calendars.

When it comes to public events, the point of focus is different, depending on whether you are an attendee (and consumer of information about the event) or are a publisher or purveyor of event information. As an individual viewer, you want to browse, aggregate, and select events, typically from multiple sources. You might be conducting these tasks in a social context. What are your friends interested in? What do they invite you to, and vice versa? Your friends might know what you care about and direct you to events you’ll find interesting. As a publisher of events, you probably want to disseminate information about the event as widely as possible. There are technical mechanisms for supporting the interchange of data between publishers of event data and consumers of event data, which is one of the subjects of this chapter.

This chapter shows the first steps to take in learning this subject:

Google Calendar

Google Calendar is fast increasing in popularity among online calendars.[232]

Let’s talk about how to use Google Calendar as a user first and then look at how to program it.

Setting Up Google Calendar As an End User

Log in to your Google account here:

http://calendar.google.com

Google Calendar has some noteworthy features:

  • In addition to creating a main calendar, you can create secondary calendars and subscribe to calendars belonging to others. Because you can turn the visibility of any given calendar on and off, you get a composite view of the events of all your visible calendars. (Think of each calendar as a layer.) On the sidebar, you get a list of your own calendars and the other calendars to which you are subscribing.

  • You can search for public events and look for public calendars.[233]

  • You can set the visibility of your calendars to one of three options: make it publicly available to everyone; show only the Free/Busy information availability, that is, show only whether a block of time is occupied; or set it to the Do Not Share with Everyone level, in which case the calendar is visible only to those people with whom you explicitly share your calendar.[234]

  • To delete a calendar, you have to click the Manage Calendars link.

  • There is Gmail/Google Calendar integration: “Gmail users can send event invitations directly from their Gmail accounts without accessing Google Calendar.”[235]

  • There is currently no direct offline access to Google Calendar.[236]

Some Usage Patterns for Google Calendar

To show some use case scenarios for Google Calendar, here I list some of the calendars that I have set up and the reasons why:

  • A strictly personal calendar for events. I have set this calendar to Do Not Share with Everyone.

  • A family and friends calendar for my closest friends. I also use the Do Not Share with Everyone setting here but then add the e-mail addresses of individual friends and family members.

  • A calendar called Raymond Yee’s Public Events to list events that I plan to be at and don’t mind the world knowing about. I use the Share All Information on This Calendar with Everyone setting.

  • A calendar called Mashup Guide Demo Calendar, a public calendar I’ll use in this chapter to demonstrate how to program Google Calendar.

When I create a new Google calendar, I consider the following factors:

  • Who I want to share the calendar with (that is, is the calendar for myself, a specific group of people, or for the whole world?)

  • The broad topic of that calendar

Sharing Calendars

There are calendar addresses that are visible to others if the calendar is public. There are three formats:[237]

  • HTML

  • iCalendar (also known colloquially as iCal)[238]

  • XML (specifically, Atom feed)

To illustrate the different feed formats, I’ll use a publicly available calendar that I created: the Mashup Guide Demo Calendar, whose sharing status I have set to Share All Information on This Calendar with Everyone.

Every Google calendar has an identifier. The user ID for a user’s main calendar is the user’s e-mail address. For other calendars, the user ID is a more complicated e-mail address. For instance, the user ID for the Mashup Guide Demo Calendar is as follows:

9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com

You can get the HTML feed for a calendar here:

http://www.google.com/calendar/embed?src={userID}

For example:

               http://www.google.com/calendar/embed?src=9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
               google.com
            

Associated with the iCalendar and XML feeds are two parameters (visibility and ­projection) that I’ll explain in greater detail in a moment. For instance, you can access an iCalendar feed here:

http://www.google.com/calendar/ical/{userID}/{visibility}/{projection}.ics

For example:

               http://www.google.com/calendar/ical/9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
               google.com/public/full.ics
            

and for example:

               http://www.google.com/calendar/ical/9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
               google.com/public/basic.ics
            

The Atom feeds are found here:

http://www.google.com/calendar/feeds/{userID}/{visibility}/{projection}

For example:

               http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
               google.com/public/basic
            

If your calendar is not public, there are still private addresses that other applications can use to access the calendar. Note that you can reset these URLs too in case you want to reset access.[239]

Exploring the Feed Formats from Google Calendar

The Google Calendar API is built upon GData, the RESTful protocol based on the Atom Publishing Protocol (APP) combined with the ­Google-­specific extensions introduced in Chapter 7.[240][241]

Before I cover how to programmatically interact with the Google Calendar, I’ll first cover what you can do by changing documents. It’s useful to take a look at specific instances of iCalendar and the XML feeds.

iCalendar is a dominant standard for the exchange of calendar data. Based on the older vCalendar standard, iCalendar is sometimes referred to as iCal, which might be confused with the name of the Apple calendaring program of the same name. The iCalendar standard is supported in a wide range of products.

The official documentation for iCalendar is RFC 2445:

http://tools.ietf.org/html/rfc2445

Some other allied standards are built around RFC 2445, but they are beyond the scope of this book:

  • iCalendar ­Transport-­Independent Interoperability Protocol (iTIP) Scheduling Events, BusyTime, ­To-­dos and Journal Entries (RFC 2446) lays out how calendar servers can exchange calendaring events.[242]

  • iCalendar Message-Based Interoperability Protocol (iMIP) (RFC 2447) covers the exchange of calendaring data by e-mail.[243]

See the Wikipedia article on iCalendar for a list of the wide range of products that support iCalendar.[244][245]

The structure of an iCalendar file is not based on XML like many of the data exchange formats covered in this book. There have been attempts to cast the iCalendar data model into XML (such as xCal[246]

iCalendar has many features, but there are a few basic things to know about it:

  • iCalendar has a ­top-­level object: VCALENDAR.

  • There are subobjects, including VEVENT, VTODO, VJOURNAL, and VFREEBUSY.

I’ll focus mostly on the VEVENT object here—though VFREEBUSY is generated in Google ­Calendar when one uses the “Share only my free/busy information (hide details)” mode.

This is a simple example of iCalendar data (with one VEVENT), quoted from RFC 2445:[247]

            BEGIN:VCALENDAR
            VERSION:2.0
            PRODID:-//hacksw/handcal//NONSGML v1.0//EN
            BEGIN:VEVENT
            DTSTART:19970714T170000Z
            DTEND:19970715T035959Z
            SUMMARY:Bastille Day Party
            END:VEVENT
            END:VCALENDAR
         

To see a more complicated instance of an iCalendar document, you can use Google ­Calendar via this:

            curl "http://www.google.com/calendar/ical/9imfjk71chkcs66t1i436je0s0%40group.Â
            calendar.google.com/public/basic.ics"
         

This gets the iCalendar rendition of my public Mashup Guide Demo Calendar, a version of which is as follows:

            BEGIN:VCALENDAR
            PRODID:-//Google Inc//Google Calendar 70.9054//EN
            VERSION:2.0
            CALSCALE:GREGORIAN
            METHOD:PUBLISH
            X-WR-CALNAME:Mashup Guide Demo Calendar
            X-WR-TIMEZONE:America/Los_Angeles
            X-WR-CALDESC:a Google Calendar to support mashupguide.net
            BEGIN:VTIMEZONE
            TZID:America/Los_Angeles
            X-LIC-LOCATION:America/Los_Angeles
            BEGIN:DAYLIGHT
            TZOFFSETFROM:-0800
            TZOFFSETTO:-0700
            TZNAME:PDT
            DTSTART:19700308T020000
            RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
            END:DAYLIGHT
            BEGIN:STANDARD
            TZOFFSETFROM:-0700
            TZOFFSETTO:-0800
            TZNAME:PST
            DTSTART:19701101T020000
            RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
            END:STANDARD
            END:VTIMEZONE
            BEGIN:VEVENT
            DTSTART;TZID=America/Los_Angeles:20070507T130000
            DTEND;TZID=America/Los_Angeles:20070507T140000
            DTSTAMP:20070510T155641Z
            ORGANIZER;CN=Mashup Guide Demo Calendar:MAILTO:9imfjk71chkcs66t1i436je0s0@Â
            group.calendar.google.com
            UID:vk021kggr20ba2jhc3vjg6p8ek@google.com
            CLASS:PUBLIC
            CREATED:20070510T021623Z
            DESCRIPTION:
            LAST-MODIFIED:20070510T021623Z
            LOCATION:110 South Hall\, UC Berkeley
            SEQUENCE:0
            STATUS:CONFIRMED
            SUMMARY:Mixing and Remixing Information Class Open House
            TRANSP:OPAQUE
            END:VEVENT
            BEGIN:VEVENT
            DTSTART;TZID=America/Los_Angeles:20070411T123000
            DTEND;TZID=America/Los_Angeles:20070411T140000
            DTSTAMP:20070510T155641Z
            ORGANIZER;CN=Mashup Guide Demo Calendar:MAILTO:9imfjk71chkcs66t1i436je0s0@Â
            group.calendar.google.com
            UID:d9btebsfd121lhqc4arhj9727s@google.com
            CLASS:PUBLIC
            CREATED:20070411T144226Z
            DESCRIPTION:
            LAST-MODIFIED:20070411T144226Z
            LOCATION:
            SEQUENCE:0
            STATUS:CONFIRMED
            SUMMARY:Day 22
            TRANSP:OPAQUE
            END:VEVENT 
            END:VCALENDAR
         

This chapter does not cover the ins and outs of the iCalendar format. I recommend the following ways to learn more about iCalendar:

In working with iCalendar, I’ve found the iCalendar Validator (http://severinghaus.org/? projects/icv/), based on the iCal4j library (http://ical4j.sourceforge.net/), to be useful. You can use it to validate the iCalendar feed for the Mashup Guide Demo Calendar:

            http://severinghaus.org/projects/icv/?url=http%3A%2F%2Fwww.google.com%2Fcalendar%2FiÂ
            cal%2F9imfjk71chkcs66t1i436je0s0%2540group.calendar.google.com%2Fpublic%2Fbasic.ics
         

Now compare Google Calendar data formatted as an Atom XML feed, which you can get using this:

            curl http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.Â
            calendar.google.com/public/basic
         

This will return a feed that looks something like this:

            <?xml version="1.0" encoding="UTF-8"?>
            <feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/Â
            opensearchrss/1.0/" 
                  xmlns:gd="http://schemas.google.com/g/2005"  
                  xmlns:gCal="http://schemas.google.com/gCal/2005">
              <id>http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar.Âgoogle.com/public/basic</id>
              <updated>2007-05-10T02:16:23.000Z</updated>
              <category scheme="http://schemas.google.com/g/2005#kind" 
                        term="http://schemas.google.com/g/2005#event"/>
              <title type="text">Mashup Guide Demo Calendar</title>
              <subtitle type="text">a Google Calendar to support mashupguide.net</subtitle>
              <link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" 
                    href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40
            group.calendar.google.com/public/basic"/>
              <link rel="self" type="application/atom+xml" 
                    href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40
            group.calendar.google.com/public/basic?max-results=25"/>
              <author>
                <name>Raymond Yee</name>
                <email>raymond.yee@gmail.com</email>
              </author>
              <generator version="1.0" uri="http://www.google.com/calendar">Google Calendar
            </generator>
              <openSearch:totalResults>2</openSearch:totalResults>
              <openSearch:startIndex>1</openSearch:startIndex>
              <openSearch:itemsPerPage>25</openSearch:itemsPerPage>
              <gd:where valueString=""/>
              <gCal:timezone value="America/Los_Angeles"/>
              <entry>
                <id>http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.Â?calendar.google.com/public/basic/vk021kggr20ba2jhc3vjg6p8ek</id>
                <published>2007-05-10T02:16:23.000Z</published>
                <updated>2007-05-10T02:16:23.000Z</updated>
                <category scheme="http://schemas.google.com/g/2005#kind" 
                          term="http://schemas.google.com/g/2005#event"/>
                <title type="text">Mixing and Remixing Information Class Open House</title>
                <summary type="html">When: Mon May 7, 2007 1pm to 2pm&amp;nbsp; PDT&lt;br&gt;  
            &lt;br&gt;Where: 110 South Hall, UC Berkeley &lt;br&gt;Event Status:     
            confirmed</summary>
                <content type="text">When: Mon May 7, 2007 1pm to 2pm&amp;nbsp; PDT&lt;br&gt;  
            &lt;br&gt;Where: 110 South Hall, UC Berkeley &lt;br&gt;Event Status:     
            confirmed</content>
                <link rel="alternate" type="text/html" Â
                      href="http://www.google.com/calendar/event?eid=dmswMjFrZ2dyMjBiYTJqaGMzdÂ
            mpnNnA4ZWsgOWltZmprNzFjaGtjczY2dDFpNDM2amUwczBAZw" title="alternate"/>
                <link rel="self" type="application/atom+xml" Â
                      href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40Â
            group.calendar.google.com/public/basic/vk021kggr20ba2jhc3vjg6p8ek"/>
                <author>
                  <name>Mashup Guide Demo Calendar</name>
                </author>
                <gCal:sendEventNotifications value="false"/>
              </entry>
              <entry>
                <id>http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
            google.com/public/basic/d9btebsfd121lhqc4arhj9727s</id>
                <published>2007-04-11T14:42:26.000Z</published>
                <updated>2007-04-11T14:42:26.000Z</updated>
                <category scheme="http://schemas.google.com/g/2005#kind" 
                          term="http://schemas.google.com/g/2005#event"/>
                <title type="text">Day 22</title>
                <summary type="html">When: Wed Apr 11, 2007 12:30pm to 2pm&amp;nbsp; 
            PDT&lt;br&gt;   &lt;br&gt;Event Status:     confirmed</summary>
                <content type="text">When: Wed Apr 11, 2007 12:30pm to 2pm&amp;nbsp; 
            PDT&lt;br&gt;   &lt;br&gt;Event Status:     confirmed</content>
                <link rel="alternate" type="text/html" Â
                      href="http://www.google.com/calendar/event?eid=ZDlidGVic2ZkMTIxbGhxYzRhcmhÂ
            qOTcyN3MgOWltZmprNzFjaGtjczY2dDFpNDM2amUwczBAZw" title="alternate"/>
                <link rel="self" type="application/atom+xml" Â
                      href="http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40Â
            group.calendar.google.com/public/basic/d9btebsfd121lhqc4arhj9727s"/>
                <author>
                  <name>Mashup Guide Demo Calendar</name>
                </author>
                <gCal:sendEventNotifications value="false"/>
              </entry>
            </feed>
         

Note the following about this data:

  • The feed is expressed in Atom format (which you learned about in Chapter 4).

  • It uses common GData extension elements,[249][250]

Using the ­GData-­Based Calendar API Directly

In this section, I will lead you through the basics of programming the Google Calendar API. Since I won’t cover all the details of the API, I refer you to “Google Calendar Data API Developer’s Guide: Protocol” documentation as an excellent place to start. You’ll learn how to set up some calendars and access the right URLs for various feeds.[251]

As with most APIs, you can take two basic approaches: you can work directly with the protocol, which in this case is based on the GData protocol that underlies many Google APIs, including that for Blogger (see Chapter 7), or you can use a ­language-­specific API kit. Here I’ll show you both approaches. Although the latter approach is often more practical, I’ll use this explication of the Calendar API as a chance to review GData (and the concepts of REST in general). To work with the specific ­language-­specific libraries, consult the documentation here:

http://code.google.com/apis/gdata/clientlibs.html

Later, I’ll give a quick rundown on how to use the PHP and Python API kits. You can get started with the documentation for the Calendar API here:

http://code.google.com/apis/calendar/developers_guide_protocol.html

The reference for the API is here:

http://code.google.com/apis/calendar/reference.html

The Google Calendar API is based on GData, which in turn is based on APP with ­Google-­specific extensions. APP is a strictly REST protocol; remember, that means resources are represented as Atom feeds, and you use standard HTTP methods (GET, POST, PUT, and DELETE) to read, update, create, and delete elements. Here I’ll show you some of the key feeds and how to use them. Before diving into doing so, I’ll first show you how to obtain an authentication token, which you need in order to make full use of these feeds (that is, beyond issuing GET requests for public feeds).

One of the two authentication methods available to you is documented here:

http://code.google.com/apis/gdata/auth.html

I’ll show you how to use the ClientLogin technique here. To make authorized access to the API, you will need an authentication token, which you can obtain by making an HTTP POST request (using the application/x-www-form-urlencoded content type) to here:

https://www.google.com/accounts/ClientLogin

with a body that contains the following parameters:

Email: Your Google e-mail (for example, raymond.yee@gmail.com)

Password: Your Google password

source: A string of the form companyName-applicationName-versionID to identify your program (for example, mashupguide.net-Chap15-v1)

service: The name of the Google service, which in this case is cl

Using the example parameters listed here, you can package the authentication request with the following curl invocation:

            curl -v -X POST -d "Passwd={passwd}&source=mashupguide.net-Chap15-v1&Email=Â
            raymond.yee%40gmail.com&service=cl" https://www.google.com/accounts/ClientLogin
         

If this call succeeds, you will get in the body of the response an Auth token (of the form Auth=[AUTH-TOKEN]). Retain the Auth token for your next calls. You will embed the authentication token in your calls by including the following HTTP request header:

Authorization: GoogleLogin auth=[AUTH-TOKEN]

[Tip]Tip

 In curl, you do so with the -H option: -H "Authorization: GoogleLogin auth=[AUTH-TOKEN]".

On occasion, you will need to handle HTTP 302 redirects from the API. That is, instead of fulfilling a request, the Google Calendar API sends you a response with a redirect URL appended with the new query parameter gessionid. You then reissue your request to this new URL.

[Tip]Tip

 For HTTP GET, use the -L option in curl to automatically handle a redirect.

Feeds Available from Google Calendar

There are three feed types: calendar (for managing calendars), event (for events contained by calendars), and comment (for representing comments attached to events). Each of the feeds isqualified by two parameters: visibility and projection. After I describe visibility and projection, I’ll list the various feeds and show how you can access them via curl. For more details about the feeds, consult this page:

http://code.google.com/apis/calendar/reference.html#Feeds

visibility and projection

There are two parameters for “specifying” the representation of feeds: visibility and projec tion. The visibility parameter can be one of public, private, or private-[magicCookie ]. Feeds that are public do not require authorization and are always ­read-­only; public feeds are inaccessible if the user has turned off sharing for the calendar. Feeds that are private do require authentication to use and are potentially writable in addition to being readable (that is, read/write). Finally, feeds that have a visibility of private-[magicCookie] are ­read-­only and enable private information to be read without authorization. (The magicCookie encapsulates authentication information.)

The projection values are listed here:

http://code.google.com/apis/calendar/reference.html#Projection

They include the following:

  • full (potentially read/write).

  • free-busy (always ­read-­only). This feed shows minimal information about events but does include data about the duration of events (in other words, the <gd:when> element).

  • basic (always ­read-­only). The basic projection produces Atom feeds without any extension elements; the <atom:summary> and <atom:content> elements contain HTML descriptions with embedded data about the events.

Calendar Feeds

There are three types of calendar feeds—meta-feed, allcalendars, and owncalendars—which I’ll cover in turn.

meta-feed

The private and ­read-­only ­meta-­feed contains an <entry> element for each calendar to which the user has access. This list includes both calendars that are owned by the user and ones to which the user is subscribed. You can access the feed at the following URL:

http://www.google.com/calendar/feeds/default

by using this:

                  curl -L -X GET -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]"  Â
                  http://www.google.com/calendar/feeds/default
               

Let’s look at an instance of an <entry>. Here is my own default calendar:

                  <entry>
                      <id>http://www.google.com/calendar/feeds/default/raymond.yee%40gmail.com</id>
                      <published>2007-10-20T18:46:01.839Z</published>
                      <updated>2007-10-19T23:18:04.000Z</updated>
                      <title type="text">Raymond Yee</title>
                      <link rel="alternate" type="application/atom+xml" Â
                            href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/Â
                  private/full"/>
                      <link rel="http://schemas.google.com/acl/2007#accessControlList" Â
                            type="application/atom+xml"Â
                            href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â
                  full"/>
                      <link rel="self" type="application/atom+xml"
                        href="http://www.google.com/calendar/feeds/default/raymond.yee%40gmail.com"/>
                      <author>
                        <name>Raymond Yee</name>
                        <email>raymond.yee@gmail.com</email>
                      </author>
                      <gCal:timezone value="America/Los_Angeles"/>
                      <gCal:hidden value="false"/>
                      <gCal:color value="#2952A3"/>
                      <gCal:selected value="true"/>
                      <gCal:accesslevel value="owner"/>
                    </entry>
               

Note the three link elements in the entry for the ­meta-­feed:

  • rel="alternate" whose href is as follows:

    http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/private/full

    If you were to do an authenticated GET on this feed, you’d see that this is an event feed containing all the events for the default calendar.

    Note how the URL of this feed maps to the following form:

    http://www.google.com/calendar/feeds/{userID}/{privacy}/{projection}

    Here the user ID is raymond.yee%40gmail.com, visibility is private, and projection is full.

  • rel="http://schemas.google.com/acl/2007#accessControlList". The following feed gives you the access control list for the given calendar.

    http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/full

    For this calendar, there is a single entry (I’m the only person who has permissions associated with my default calendar):

                            <entry> <id>http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â
                            full/user%3Araymond.yee%40gmail.com</id>
                                <updated>2007-10-20T23:14:47.000Z</updated>
                                <category scheme="http://schemas.google.com/g/2005#kind"
                                  term="http://schemas.google.com/acl/2007#accessRule"/>
                                <title type="text">owner</title>
                                <content type="text"/>
                                <link rel="self" type="application/atom+xml" Â
                                      href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â
                            full/user%3Araymond.yee%40gmail.com"/>
                                <link rel="edit" type="application/atom+xml" Â
                                      href="http://www.google.com/calendar/feeds/raymond.yee%40gmail.com/acl/Â
                            full/user%3Araymond.yee%40gmail.com"/>
                                <author>
                                  <name>Raymond Yee</name>
                                  <email>raymond.yee@gmail.com</email>
                                </author>
                                <gAcl:scope type="user" value="raymond.yee@gmail.com"/>
                                <gAcl:role value="http://schemas.google.com/gCal/2005#owner"/>
                              </entry>
                         
  • rel="self"

    http://www.google.com/calendar/feeds/default/raymond.yee%40gmail.com

    This feed returns one entry for the default calendar—instead of all the calendars to which the user (raymond.yee@gmail.com) has access.

allcalendars

The allcalendars feed is a private, potentially read/write feed for controlling subscriptions and settings (such as the display color) for calendars. Inserting or deleting entries to the allcalendars feed is tantamount to subscribing or unsubscribing to existing calendars. You can update personalization settings for your calendars: the color, whether it is hidden, and whether it is selected. You can’t create or delete calendars by manipulating the allcalendars feed; for those actions, you need to use the owncalendars feed.

The URL for the allcalendars feed is here:

http://www.google.com/calendar/feeds/default/allcalendars/full

which you can access with this:

                  curl -L -X GET -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]"  Â
                  http://www.google.com/calendar/feeds/default/allcalendars/full
               
[Note]Note

 You might wonder about the difference between meta-feed and allcalendars since both of them list all the calendars to which a user has access. The allcalendars feed with a projection value of full is read/write, while the meta-feed is ­read-­only. If you try to access the allcalendars feed with a projection value of basic (to get something akin to the ­meta-­feed), you’ll get an “unknown visibility found” error.

I’ll now walk you through how to manipulate the allcalendars feed to add and delete a subscription to the Phases of the Moon calendar, one of Google’s public calendars, which is available here:

                  http://www.google.com/calendar/embed?src=ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.Â
                  google.com
               

Note the user ID of the calendar:

ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com

To subscribe to the calendar, create a file (called phases_moon_entry.xml) with the minimal entry element needed to be the body of the post as follows:

                  <?xml version='1.0' encoding='UTF-8'?>
                  <atom:entry xmlns:atom="http://www.w3.org/2005/Atom">
                    <atom:id>ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com</atom:id>
                  </atom:entry>
               

Next, issue an HTTP POST request:

                  curl -v  -X POST --data-binary "@phases_of_moon_entry.xml"  -H "Content-Type: Â
                  application/atom+xml "  -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]" Â
                  http://www.google.com/calendar/feeds/default/allcalendars/full
               

As mentioned earlier, there’s a good chance you’ll get a 302 HTTP response code to this call:

                  http://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=Â
                  {gessionid}
               

For example:

                  http://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=Â
                  GUWxgPh61GQ
               

If you do get a 302 HTTP response code, reissue the call to the new URL with this:

                  curl -v  -X POST --data-binary "@phases_of_moon_entry.xml" -H "Content-Type: Â
                  application/atom+xml "  -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]" Â
                  http://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=Â
                  {gessionid}
               

If the request to subscribe to the Phases of the Moon calendar is successful, you’ll get a 201 HTTP response code to indicate a created calendar, along with a response body akin tothis:

                    <entry> <id>http://www.google.com/calendar/feeds/default/allcalendars/full/Â
                  ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com</id>
                      <published>2007-10-20T23:55:52.611Z</published>
                      <updated>2007-10-14T07:19:30.000Z</updated>
                      <title type="text">Phases of the Moon</title>
                      <summary type="text"/>
                      <link rel="alternate" type="application/atom+xml" Â
                            href="http://www.google.com/calendar/feeds/ht3jlfaac5lfd6263ulfh4tql8%40Â
                  group.calendar.google.com/private/full"/>
                      <link rel="self" type="application/atom+xml"Â
                            href="http://www.google.com/calendar/feeds/default/allcalendars/full/Â
                  ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com"/>
                      <link rel="edit" type="application/atom+xml" Â
                            href="http://www.google.com/calendar/feeds/default/allcalendars/full/Â
                  ht3jlfaac5lfd6263ulfh4tql8%40group.calendar.google.com"/>
                      <author>
                        <name>Phases of the Moon</name>
                      </author>
                      <gCal:timezone value="Etc/GMT"/>
                      <gCal:hidden value="false"/>
                      <gCal:color value="#7A367A"/>
                      <gCal:selected value="false"/>
                      <gCal:accesslevel value="read"/>
                      <gd:where valueString=""/>
                    </entry>
               

You can then unsubscribe to the Phases of the Moon calendar with the following HTTP DELETE request:

                  curl -v -X DELETE -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]" Â
                  http://www.google.com/calendar/feeds/default/allcalendars/full/ht3jlfaac5lfd6263ulfhÂ
                  4tql8%40group.calendar.google.com?gsessionid={gsessionid}
               
owncalendars

The owncalendars feeds hold data about the calendars that a user owns. This feed is conceptually similar to the allcalendars feed, with one important difference. Instead of subscribing and unsubscribing to calendars, actions on the owncalendars feed are equivalent to creating and destroying calendars. The syntax for manipulating the owncalendars feed is similar to that for the allcallendars feed. For instance, to retrieve the feed, do a GET to this:

http://www.google.com/calendar/feeds/default/owncalendars/full

For example:

                  curl -v -L -X GET -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]" Â
                  http://www.google.com/calendar/feeds/default/owncalendars/full
               

To create a new ­book-­writing calendar, create a file entitled book_writing_calendar_entry.xml:

                  <?xml version="1.0" encoding="UTF-8"?>
                  <entry xmlns='http://www.w3.org/2005/Atom' 
                    xmlns:gd='http://schemas.google.com/g/2005' 
                    xmlns:gCal='http://schemas.google.com/gCal/2005'>
                    <title type='text'>Book Writing Schedule</title>
                    <summary type='text'>A calendar to track when I write my book.</summary>
                    <gCal:timezone value='America/Los_Angeles'></gCal:timezone>
                    <gCal:hidden value='false'></gCal:hidden>
                    <gCal:color value='#2952A3'></gCal:color>
                    <gd:where rel='' label='' valueString='Berkeley, CA'></gd:where>
                  </entry>
               

and do the following POST (after handling the HTTP 302 redirect):

                  curl -v  -X POST --data-binary "@book_writing_calendar_entry.xml"  -H "Content-Type: Â
                  application/atom+xml "  -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]" Â
                  http://www.google.com/calendar/feeds/default/owncalendars/full?gsessionid=Â
                  {gsession-id}
               

Furthermore, you can then update an existing calendar by issuing the appropriate PUT:

http://www.google.com/calendar/feeds/default/owncalendars/full/{userID}

And you can delete an existing calendar by using DELETE:

http://www.google.com/calendar/feeds/default/owncalendars/full/{userID}

Event Feeds

Now that you have studied the three types of calendar feeds, you’ll look at how to use the event feeds. (I won’t cover comment feeds in this book.) Specifically, let’s look at the simple case of retrieving all the events from a given feed for which you have write privileges. To work with a given calendar, you need to know its user ID. In the instance of my own calendars (the Mashup Guide Demo calendar), the user ID is as follows:

9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com

The syntax of the URL to the feed of the events is as follows:

http://www.google.com/calendar/feeds/{userID}/{privacy}/{projection}

Specifically, you can use a privacy value of public and a projection value of full since the calendar is a public one to arrive here:

http://www.google.com/calendar/feeds/{userID}/public/full

For example:

               http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
               google.com/public/full
            

which you can confirm is a URL to a feed of all the events on the calendar. To add an event, you need to send an HTTP POST request (with the proper authentication) here:

http://www.google.com/calendar/feeds/{userID}/private/full

For example:

               http://www.google.com/calendar/feeds/9imfjk71chkcs66t1i436je0s0%40group.calendar.Â
               google.com/private/full
            

That is, you create a file by the name of project_showcase_event.xml with the following content:

               <?xml version='1.0' encoding='UTF-8'?>
               <entry xmlns='http://www.w3.org/2005/Atom'
                 xmlns:gd='http://schemas.google.com/g/2005'>
                 <category scheme='http://schemas.google.com/g/2005#kind'
                   term='http://schemas.google.com/g/2005#event'></category>
                 <title type='text'>Project Showcase</title>
                 <content type='text'>A chance for the class to show off their projects</content>
                 <gd:where valueString='110 South Hall'></gd:where>
                 <gd:when startTime="2008-05-12T13:00:00.000-07:00" 
                          endTime="2008-05-12T14:00:00.000-07:00"/>
               </entry>
            

and issue the following request:

               curl -v  -X POST  --data-binary "@project_showcase_event.xml"  -H "Content-Type: Â
               application/atom+xml "  -H "Authorization: GoogleLogin  auth=[AUTH-TOKEN]" Â
               http://www.google.com/calendar/feeds/{userID}/private/full?gsessionid={gsessionid}
            

where the gsessionid is the one given in the 302 redirect to create an event on the Mashup Guide Demo calendar.

With an analogous procedure to how you subscribe or unsubscribe to calendars in the allcalendars feed or create calendars through the owncalendars feed, you can create and delete events through the events feed.

Using the PHP API Kit for Google Calendar

Working directly with the GData interface to Google Calendar gives you a lot of flexibility at the cost of tedium. Now we’ll turn to studying how to use two of the API wrappers for Google Calendar. In the next section, I’ll show you how to use the Python API kit. Here, we’ll study the PHP wrapper.

The PHP API kit is documented here:

http://code.google.com/apis/calendar/developers_guide_php.html

The PHP library for accessing Google Calendar is part of the Zend Google Data Client Library, which, in turn, is available as part of the Zend Framework or as a separate download. Note that the library is developed by Zend and works with PHP 5.1.4 or newer. You can download the Zend Framework from this location:

http://framework.zend.com/

You can read about how to use the Zend Framework to access Google Calendar here:

http://framework.zend.com/manual/en/zend.gdata.calendar.html

You install the Zend framework by copying the files to a directory of your choice. I set up the Zend Framework in this location:

http://examples.mashupguide.net/lib/ZendFramework/

I’ll now illustrate the basics of using this library through two code snippets. Both use the ClientLogin form of authorization. The first example retrieves a list of a user’s calendars:

            <?php
            
            require_once 'Zend/Loader.php';
            Zend_Loader::loadClass('Zend_Gdata');
            Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
            Zend_Loader::loadClass('Zend_Gdata_Calendar');
            
            function getGDataClient($user, $pass)
            {
              $service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
            
              $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
              return $client;
            }
            
            function printCalendarList($client)
            {
              $gdataCal = new Zend_Gdata_Calendar($client);
              $calFeed = $gdataCal->getCalendarListFeed();
              echo $calFeed->title->text . "\n";
              echo "\n";
              foreach ($calFeed as $calendar) {
                echo $calendar->title->text, "\n";
              }
            }
            
            $USER = "[USER]";
            $PASSWORD = "[PASSWORD]";
            
            $client = getGDataClient($USER, $PASSWORD);
            printCalendarList($client);
            
            ?>
         

The second code sample retrieves a list of events for a given calendar and prints basic elements for a given event: its ID, title, content, and details about the “where” and “when” of the event:

            <?php
            
            require_once 'Zend/Loader.php';
            Zend_Loader::loadClass('Zend_Gdata');
            Zend_Loader::loadClass('Zend_Gdata_ClientLogin');
            Zend_Loader::loadClass('Zend_Gdata_Calendar');
            
            function getGDataClient($user, $pass)
            {
              $service = Zend_Gdata_Calendar::AUTH_SERVICE_NAME;
            
              $client = Zend_Gdata_ClientLogin::getHttpClient($user, $pass, $service);
              return $client;
            }
            
            function printEventsForCalendar($client, $userID)
            {
              $gdataCal = new Zend_Gdata_Calendar($client);
            
              $query = $gdataCal->newEventQuery();
              $query->setUser($userID);
              $query->setVisibility('private');
              $query->setProjection('full');
            
              $eventFeed = $gdataCal->getCalendarEventFeed($query);
            
              echo $eventFeed->title->text . "\n";
              echo "\n";
              foreach ($eventFeed as $event) {
                echo $event->title->text, "\t", $event->id->text, "\n" ;
                echo $event->content->text, "\n";
                foreach ($event->where as $where) {
                  echo $where, "\n";
                }
                foreach ($event->when as $when) {
                  echo "Starts: " . $when->startTime . "\n";
                  echo "Ends: " . $when->endTime . "\n";
                }
                
                # check for recurring events
                if ($recurrence = $event->getRecurrence()) {
                  echo "recurrence: ", $recurrence, "\n";
                } 
                
                print "\n";
              }
            }
            
            $USER = "[USER]";
            $PASSWORD = "[PASSWORD]";
            
            # userID for the Mashup Guide Demo calendar
            $userID = "9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com";
            
            $client = getGDataClient($USER, $PASSWORD);
            printEventsForCalendar($client, $userID);
            
            ?>
         

Later in the chapter, you will see how to use the PHP Google Calendar library to create events.

Using the Python API Kit for Google Calendar

You can find the documentation on the Python API kit here:

http://code.google.com/apis/calendar/developers_guide_python.html

To install the library, you can download it from here:

http://code.google.com/p/gdata-python-client/downloads/list

Or you can access the access the Subversion repository for the project here:

http://gdata-python-client.googlecode.com/svn/trunk/

[Note]Note

 The following code depends on the ElementTree library, which ships with Python 2.5 and newer. You can find instructions for downloading ElementTree at http://effbot.org/zone/element-index.htm.

Here’s some Python code to demonstrate how to list all of your calendars and to list the events on a specific calendar:

            """
            Chapter 15:  simple facade for Python Google Calendar library
            """
            __author__ = 'raymond.yee@gmail.com (Raymond Yee)'
            
            EMAIL = '[USER]'
            PASSWORD = '[PASSWORD]'
            
            try:
              from xml.etree import ElementTree
            except ImportError:
              from elementtree import ElementTree
            
            import gdata.calendar.service
            import gdata.calendar
            import atom
            
            class MyGCal:
                def __init__(self):
                    self.client = gdata.calendar.service.CalendarService()
                    self.client.email = EMAIL
                    self.client.password = PASSWORD
                    self.client.source = 'GCalendarUtil-raymondyee.net-v1.0'
                    self.client.ProgrammaticLogin()
                def listAllCalendars(self):
                    feed = self.client.GetAllCalendarsFeed()
                    print 'Printing allcalendars: %s' % feed.title.text
                    for calendar in feed.entry:
                      print calendar.title.text
                def listOwnCalendars(self):
                    feed = self.client.GetOwnCalendarsFeed()
                    print 'Printing owncalendars: %s' % feed.title.text
                    for calendar in feed.entry:
                      print calendar.title.text
                def listEventsOnCalendar(self,userID='default'):
                  """
                  list all events on the calendar with userID
                  """
                  query = gdata.calendar.service.CalendarEventQuery(userID, 'private', 'full')
                  feed =  self.client.CalendarQuery(query)
                  for event in feed.entry:
                    print event.title.text, event.id.text, event.content.text
                    for where in event.where:
                      print where.value_string
                    for when in event.when:
                      print when.start_time, when.end_time
                    if event.recurrence:
                      print "recurrence:", event.recurrence.text
            
            if __name__ == '__main__':
                gc = MyGCal()
                gc.listAllCalendars()
                # userID for Mashup Guide Demo calendar    
                userID = '9imfjk71chkcs66t1i436je0s0%40group.calendar.google.com'
                gc.listEventsOnCalendar(userID)
         


[230] SyncML is now known as Open Mobile Alliance Data Synchronization and Device Management.