Thursday, August 24, 2006

Creating a portable calendar RSS feed for Exchange with SSE extensions – version 0.5

A few years ago I came up with this simple RSS feed for a Exchange calendar that used an Exchange store event sink to generate a feed of calendar items for a certain number of days. This was a fun thing to do at the time maybe not that useful at the end of the day because it lacks the ability to be able to integrate it into anything really live. The other day someone asked me about SSE which is “The objective of Simple Sharing Extensions (SSE) is to define the minimum extensions necessary to enable loosely-cooperating apps”. Put basically its about creating wiring or a method that will allow too endpoints (whatever they are) to exchange and share data easily. For example you could syndicate your family’s calendars so In Outlook you would have side-by-side or maybe in a different calendar appointments from family members etc that you subscribed to via a normal RSS feed you can then syndicate this information to other people in a combined RSS etc. Now that sounds really simple by like most things in life well …. . Putting everything else aside for a moment there are some very cool technologies coming online that are going to facilitate all this microformats is a good example where they have evolved the ical format into hcalendar.

This really got me thinking about how to make an exchange calendar portable currently a calendar sitting inside a Exchange Database can present some challenges to anybody wanting to take it and synchronize it with another end point. But there are a few cool bits and pieces in the existing Exchange API’s that can help aid this. For instance if you look at the stream of an appointment item with CDOEX or WebDAV you can retrieve the vCalendar message part of the item which basically contains enough information to recreate that appointment on another device or calendar. (with the notable exception of some MAPI properties). The other thing that is in the current exchange API which is useful for this type of project is WebDAV replication. WebDAV replication is a replication mechanism to synchronize changes against a defined collection have a look at this for more detail.

As a starting point feed what I decided to try and do was create a RSS feed that represented the items in a Exchange Calendar. Now because an appointment can be reoccurring and have exceptions this can start to become a little cloudy and complicated. One assumption that this feed makes is that there will be enough information in the Rrule and ExRule of the master instance of the appointment to reconstruct all the appointments (one problem is that Exchange doesn’t seem to follow the spec in regards to the ExRule so I although the RRule did work okay the EXrule didn’t seem to work at all). The other thing I did with this feed is that I haven’t included a time windows so it’s a raw output of all the items that are in the calendar. There where a couple of reasons for this one is that with WebDAV replication you have to specify a query that represents that collection you’re replicating. If you start modifying the dates of this query you’re using this makes the collblob you have invalid and you start the replication from scratch each time. The other problem is that if you try to time limit the query you need to start worrying about expanding reoccurring appointments etc. So the method I used was a little simpler in that the collection I used excludes any expanded items and only includes master instances of recurring appointments and the normal appointment objects the downside of this is that you get every object which includes those appointments from the past. On a calendar with a lot of appointments this could make the feed file quite large.

Because this feed is designed to sync an exchange calendar most probably with another exchange calendar I decided to create my own namespace to use in the RSS feed file. Extendeding RSS is pretty easy this is basically what the SSE spec does as well but I’ve just create a new namespace so I could firstly store the colbbloob and some other information such as the StoreEntryID of the object. The information I think will come in handy when you go to recreate the object in the exchange store or you are working on conflict resolution. For a description of the namespace I created and what the properties do and are for I’ve put up a quick namespace definition here .

The feed itself essentially contains the Vcalendar message part of the appointment in an Exchange calendar contained as a CDATA part of the description element of an item in the RSS feed. Using the CDATA part means the Vcalendar part can be stored “as is” in the feed file which means that it should be able to be used at the other end without any problems. This is where the hcalender spec would could in handy because it defines a proper XML spec for the ical information one reason for not using it that it would have required extra code to do the translation. I hope to do this in a future version though (sometime).

To incorporate the SSE spec from Microsoft I’ve included the SSE namespace declarations at the start of the RSS feeds as well as the required version tag. As at the time of writing the version of the SSE spec I used was .91 I expect this would change and make this whole thing completely invalid (hey you’ve got love technology). The main SSE changes are implemented within the item element where the sx:sync and sx:history elements are used to track the version on the calendar appointment and its change history. I’ve used the storeEntryID as the sync ID as this should be unique across any store this appointment is replicated to and can also be usefully for locating the appointment or resolving conflicts as needed. The other change tracking elements are added as per the existing .91 spec where delete items are represented by setting the deteleted attribute to true and maintaining the tombstone. The only thing I did with the delete function in the code is that I make it also remove the Vcalendar message part from the description element this was mainly to conserve space with the feed itself. One part of the SSE spec that is not implemented in the code is conflict resolution this is something that really needs to be done later by the agents that may be reading this feeds and incorporating the change into a calendar and I haven’t really gotten that far yet so this is a to do. A sample of what the feed it produces looks like is here.

What doesn’t work: Well exceptions to recurring appointments pulling the VCalendar body part from the Exchange store is a great way to say time in the code but because of the intricacies of MAPI the accuracy of this method doesn’t really seem to be there this means I really need to change the method Im using for the next version of this although I still think webdav replication will still be a good method of tracking changes on a collection.

Where to next after the things I’ve learned while writing this script I really think I need to change track. Firstly going from ical to hcalendar would make this thing a lot more functional when it comes to integrating into non exchange end points (eg Sunbird/lightning etc). Also going to a time windowed feed and writing a proper Mapi to hcalander library is really needed to do this properly. So this means its time to ditch the script and write some proper class libraries.

To run this code because it uses WebDAV replication you need to schedule it to run at regular intervals to check for updates. The flow of the code is such when it’s first runs it checks to see if the feed file exists and if it does it opens the file and retrieves the collblob from the file. If the file doesn’t exist then it creates the file and does a query with a blank collblob this will return all items in the collection. The DAV:href returned by the replication query is used to get the stream of each of the items in the collection and create a corresponding item in the xml feed. When the file does exist and there is a current collblob it makes a query with that blob which the retireves the manifest of changes. The logic in the script then processes this as changes, deletes or additions. As the GUID I’ve used the repl-uid which allows the location in the feed of any item that gets changed in the replication manifest.

Well that’s about it this is still very much a work in progress and at the moment I’m more inclined as I said to start developing the hcalendar side of this process rather then the agent that would make it useful in synchronization. I posted a downloadable copy of the code I talked about here there’s a FBA and non FBA version depending on what authentication you running on you server the variables in the top of the code you need to fill in are pretty self explanatory. I wont post the code itself because it just too large.

No comments: