CalDAV on iPhone OS 3.0

After all my frustration with iPhone notes, tasks, and events that led to my purchase of Things,* Apple has finally added preliminary support for CalDAV in iPhone OS 3.0. Along with their CalendarServer (which, while only bundled with Mac OS X Server, is implemented in Python and 100% open source) you can setup a decent calendaring server for your network. Here’s how I did it:

First, Apple’s svn repository for CalendarServer isn’t that large, but the setup process downloads lots of bits separately, so make a working directory:

mkdir ~/caldav
cd caldav

Fetch the project from the repository:

svn co http://svn.calendarserver.org/repository/calendarserver/CalendarServer/trunk CalendarServer

In addition to Darwin, Apple has gone out of their way to make things work nicely in Linux and FreeBSD. Most of the work will be done by the run Python script in this directory. You will need at least Python 2.5 for this. The script has two modes, one to set everything up, and one to run the server. First, lets set everything up:

./run -s

This will download lots of extra projects into the parent directory that CalendarServer is in, so if you skipped that first step, you’re going to have a mess wherever the repository was pulled to. The projects downloaded include:


CalDAVTester
PyKerberos
PyOpenDirectory
PyXML-0.8.4
Pyflakes
Twisted
libevent-1.4.8-stable
memcached-1.2.6
pyOpenSSL-0.7
pydirector-1.0.0
python-dateutil-1.4.1
select26-0.1a3
vobject
xattr
zope-interface-3.3.0

Your version numbers may vary somewhat depending on when you pull down the code. The script will compile anything that needs it, and set it all up for you. The only thing you really need to be careful about is the xattr package. Here’s why:

xattr

This package is a PHP interface for getting and setting Extended Attributes (known as xattrs or EAs) in filesystems. These are essentially extra bits of info in addition to normal attributes like owner, permissions, and timestamp. For this package to work for you, your filesystem must support xattrs. How do you know if it does? If you are using Darwin with HFS+, it’s built in. Likewise if you are using XFS under Linux, its built in and you don’t need to do anything extra. If you are using EXT3 under Linux, your filesystem driver must be compiled with CONFIG_EXT3_FS_XATTR=y and mounted with the user_xattr option. CalendarServer absolutely depends on xattrs to work, and there’s no way around this. So before going any further, take the time to research your filesystem to see if it supports xattrs and how to enable them if it does.

In Linux, you can test for xattr support using setfattr and getfattr:

setfattr -n user.foo -v ‘blah blah’ file

getfattr -d -m ” file
file: file
system.posix_acl_access=0sAgAAAAEABgD
user.foo=”blah blah”

If that works for you, you have xattr support and you can proceed.

After run -s completes, CalendarServer is essentially setup and ready to run, but you’ll want to at least setup some accounts first.
Open CalendarServer/conf/auth/accounts.xml in your favorite text editor.

The first key you see will be for the realm, where some users are defined. If you do nothing else, change the default passwords on the admin and test accounts. And you probably want to go ahead and just change the test account to be one you will use. You can also change the members of the default group to add your name to it.

Now let’s look at the configuration files for the server in CalendarServer/conf. You’ll see 3 of them:

caldavd-apple.plist
caldavd-dev.plist
caldavd.plist

The first and last ones are default plists that would be typical for use in a Mac OS X Server environment. The options are somewhat different, such as paths for data and other configuration, and it tells the server to use DirectoryService instead of the flat XML file for accounts. But for this code that has been checked out of SVN, the run script has been modified to use caldavd-dev.plist, a simpler, leaner config file that works with what you downloaded. You can safely ignore, or even remove the other 2 files, but you may want to keep them around for reference.

Any changes you make will be to caldavd-dev.plist.

I changed my DocumentRoot to a more sensible location: /var/www/caldav/data/ and moved everything in twistedcaldav/test/data/ to there. I also changed location of the logs, socket, and pid files to /var/log/CalendarServer and /var/run respectively.

To run CalendarServer, just execute:

./run

Without the -s. Note that it will not run as root.

Now you should be able to connect to your server on port 8008 (or 8443 for SSL) from any CalDAV client such iCal. In iPhone OS 3.0, Calendar.app doesn’t yet work with SSL CalDAV connections. For the base URL, just enter the server name and it will add the rest automatically.

Now with both iCal and the iPhone working on the same CalDAV server, it doesn’t matter where you manage your calendar, they always stay in sync. This is the idea, at least. In practice, I have found a bug in the 3.0 beta. The iPhone will not refresh and remove events that were deleted by another client. To clarify:

If you add an event on the iPhone, it will appear in iCal
if you edit an event on the iPhone, it will change in iCal
If you remove an event from the iPhone, it will remove from iCal

and the reciprocal…

If you add an event in iCal, it will appear on the iPhone
If you edit an event in iCal, it will change on the iPhone
X If you remove an event in Cal, it will not remove on the iPhone

I have tested this extensively using all possible options, and running the server on both Linux and Darwin, and it makes no difference. Watching the CalendarServer access.log tells me that when the event is removed from iCal, it actually is deleted on the server. It’s simply that the iPhone’s view won’t refresh and remove it. Attempting to remove it again from the iPhone does indeed get rid of it on the iPhone side, but then it ignorantly tries to tell the server to remove it and the server logs a “file not found” since it’s already gone. It would seem that at least for the 3.0 beta, the only sure way to make the iPhone not show a deleted event is to actually perform the delete from the iPhone. This will no doubt be fixed by release day.

UPDATE 5/2/2009: since beta 3, this is fixed.

*ToDos still aren’t implemented on the iPhone, so I’ll be sticking with Things indefinitely, and that’s fine by me. It is a fantastic app.