Sharing, Syncing and editing iCal over WebDAV
iCal. Such a nice calendering application that is, and a pioneer in the vastly used ics calendar format. Is it the ultimate calendar ever? Well, almost.
What drove me insane was that, while you can publish your calendars to a WebDAV server for others to see and subscribe to, you cannot edit the calendars that are published — unless you have a .mac account. While I sincerly hope this will be in Leopard, I’m not holding my breath.
You see, I run Linux on my desktop at home, and Mac OS X on my laptop, for work. I just wanted to find a simple way to share my calendar between the two machines, and to be able to edit them on any machine.
And it just so happens I just have the solution.
Configuring the WebDAV server
Now, vast amounts of documentation can be found on the subject of setting up the WebDAV server. I’m not going to insult those who already worked on the problem by needlessly rewriting the instructions here. However, I will give you pointers.
- Enabling WebDAV on Apache [serverwatch.com]
- WebDAV on OS X With iCal [gregwestin.com]
- iCal Exchange (Free ics hosting)
- Free WebDAV Hosting [box.net]
So you could go ahead and setup your WebDAV server on *nix or OS X using the two first links, or you could just get free WebDAV hosting using the two others. Any will do.
For the sake of completeness, I will add my own WebDAV configuration below, on Gentoo Linux with Apache 2. I just installed mod_dav on apache2, and added the following configuration to /etc/apache/modules.d/10_mod_dav.conf:
<IfModule mod_dav.c>
DAVLockDB /var/lock/mod_dav/Dav_Lock
Alias /ical /var/dav/davroot
DavMinTimeout 600
<Directory /var/dav/davroot>
Dav On
Options +Indexes
AllowOverride None
AuthType Digest
AuthName "ical-webdav"
AuthDigestFile /var/dav/htpasswd.digest
Require valid-user
Order allow,deny
Allow from All
</Directory>
</IfModule>
Of course, I just then added a user using htdigest. You could use “AuthType Basic” if you don’t use mod_digest.
I tested the WebDAV functionality using the OS X “Connect to server” Function. Just enter the path to your webdav location.

I was prompted for authentication. Upon submitting my credentials, the drive was mounted on the desktop.

You should test to see if you can write files to the WebDAV folder. Once that’s done, we can move on the beef of this article.
Setting up iCal
You should take care of iCal first. First thing first, go ahead and share your calendar via iCal, as usual. Enter your WebDAV server information.

Once all is published and well, according to the little icon next to your calendar (
), you have successfully published your calendar in a perfect read only fashion.
Making iCal Sync from the server
This is the sweet part, the core of this article. Now, we want iCal to also download the changes from the server. For this purpose, you must find out the Path of your corestorage.ics file for that calendar. Go have a look in ~/Libary/Application Support/iCal/Sources/, right now. (That being the “Library” folder from your Home Directory).

You should see some folder(s) with ugly names, one per Calendar you have. There’s no easy step to this, but you have to find out which is which. You can judge either by creation dates, or by opening the .ics file in your favorite text editor to see if you recognize some of the contents. Of course, if you only have one calendar, things are simplified, you will just have one folder, and one file.
In any case, write down the absolute path to the folder containing the ics file, it’s important. For instance, in my case, it turns out to be:
/Users/supernaut/Library/Application Support/iCal/Sources/2FBCA21F-80E0-44FD-B47A-ED34AE652010.calendar
ical_sync.sh
I have then written two scripts that take care of downloading, comparing and synchronizing your calendars from the WebDAV server. You will need the following utilities installed, most are available from Fink.
- wget
- md5sum
Download and place the following script somewhere on your system. I created a folder named “bin” in my home directory and placed it there.
Next, edit the script and change the variables to match your situation, eg:
ICALPATH="/you/core/ics/folder"
WEBDAV="http://www.yourserver.com/path/to/dav/folder/calendar.ics"
LOGIN="yourlogin"
PASSWORD="yourpassword"
WGET="/sw/bin/wget"
MD5SUM="/sw/bin/md5sum"
Remember! The value for $ICALPATH is actually the one you wrote down earlier. Don’t worry if you mess it up, the script will warn you.
Once that’s done, run it in terminal. It should tell you if ANYTHING goes wrong and back off. I made it extra careful, it would suck to wreck your calendar because the server is down or answers strange things.
This will indeed download and update your calendar on your Mac from the WebDAV server. But how will you make this happen automagically? Well, I have taken care of that too.
Working the Applescript magic
Turns out I have written a second script, this time, an applescript one. You can download the source over there.
Open it or paste it in Script Editor. You should then change the line
do shell script "bash /Users/supernaut/bin/ical_sync.sh"
to match the location of the ical_sync.sh script and then hit “compile”.
Once that’s done, just save it somewhere, but make sure you save it:
- As an Application
- Make sure the startup screen is unchecked

Once that’s done, simply replace the iCal icon in your dock by this script. You can add a pretty icon to it to make it more bearable.

Everytime you click on iCal then, it will sync up the calendar from the server, and tell if you if anything goes wrong. It will then proceed to launch the real iCal for you.
The AppleScript will show a dialog box if, say, the network is down, or something went wrong. For example:

You can then take action. As a precaution, in the event that it wasn’t what you wanted to do, the script will ask you if you still want to launch iCal.

I made it that way because, sometimes, you might want to look at your calendar without being connected to the internet. Makes sense, right?
Now, onwards to other Calendaring software.
Configuring Other Calendars
Nearly any other Calendaring software will not only fetch the lastest ics file from a webdav server, but will also write it back on change, or upon instruction to do so. This means, no problems whatsoever.
I use Korganizer in conjunction with Kontact on my KDE based desktop. Evolution and Sunbird could most likely do this as well.
I just added a calendar for a web source, and configured it with my WebDAV information:

Please excuse the craptacular quality of the screenshot. It was taken while forwarding X11 to my Mac over an SSH tunnel, and as such, fonts are screwy.
Then, it just worked out of the box. No problem whatsoever.
In conclusion
This is somewhat of a cheap and dirty hack, but it works fairly well. I’ve been using it for three weeks and it’s a dream.
I sincerely hope that this has been somewhat useful to at least someone
Drop me a comment if you liked it, or if you have problems. Feel free to ask, really.

Against TCPA
August 17th, 2006 at 11:32 am
The shell scripting is a very clever idea and pretty well written, too. However, a much cleaner way of automating the process would be to use a Cron job that ran every 5 minutes or so.
August 17th, 2006 at 1:53 pm
I thought of the cronjob idea at first, but then again, I was afraid of what it would do if say, network was down, and if not, the shell script actually downloads the file everytime it is ran for comparison. And downloading that file every five minutes didn’t feel really polite. So I decided to run it on startup.
(Also, what happens if the file is updated while iCal is running?)
August 17th, 2006 at 2:41 pm
Hmm…perhaps every 5 minutes is a little on the heavy side; I run my own WebDAV server, though, so I’m less considerate of my own equipment. Every 30 minutes or every hour wouldn’t be out of the question, though
To only run when there’s a connection, call a shell script with this at the beginning:
/sbin/ping -c 1 [your_server] 2>&1 >/dev/null
if [ $? -ne 0 ]
then
exit
fi
$? is the exit code of the last command (ping, in this case). Ping returns 0 if everything went well. If it can’t connect, it’s going to return a non-zero value.
File updates while iCal is running are an issue, though. I experimented with manually editing one of the iCalendar files, and iCal completely ignored it. Maybe some sort of Applescript to reload or something?
August 17th, 2006 at 2:58 pm
It’s possible to add checking if network is up to above script, and if it’s up then syncs.
if [
ping -c 1 -t apple.com > /dev/null; echo $?-eq 0 ]then
bash /Users/USERNAME/bin/ical_sync.sh
fi
And put it into crond.
August 17th, 2006 at 3:14 pm
Less than perfect, but you could just use Applescript to quit and restart iCal. That causes it to reload all the calendars. The following is the best I’ve been able to come up with (n.b.: I have no Applescripting experience):
tell application "iCal" to quit
delay 1
tell application "iCal" to launch
tell application "Finder" to set visible of every process whose name is "iCal" to false
Notes:
If the delay isn’t there, I think the script tries to relaunch iCal before it’s finished quitting, so it doesn’t do anything.
I haven’t found any way to actually hide iCal on launch, the best I could find was hiding it immediately after it loads.
August 17th, 2006 at 3:58 pm
It has never occured to me to check if the server was up before, I was more preoccupied with handling the occurence that it was down…
Technically, I believe wget can be set to send an HTTP HEAD request and exit with 1 on failure. I could have used that. I could also have used the wget –timestamping option to decide weither or not to download the file, but I thought that since it was a “once per run” affair, md5 was safer. I don’t trust timestamps.
And also, if the server is down, using this method, it will just exit with 1, and if you use the crappy AppleScript I cooked up, it should just tell you “This didn’t work. Do you want iCal anyways?”, which is all good.
I’m not entirely convinced by restarting iCal automatically. What if I’m editing something and it restarts now? What if if there is a dialog box?
If you have the LWP::Simple Perl module installed, this could also be used:
perl -e 'use LWP::Simple;if(LWP::Simple::head("http://www.server.com/dav/file.ics")){exit 0;}else{exit 1;}'
Ping is a bad idea in my case because my Cisco PIX would respond to ICMP regardless of if the web server behind was down or not.
But wget timestamping is something I will look into when I get home.
Kontact and Korganizer on the other hand are fine because I configured the source to automatically reload every 1 minute, and write changes only when they are commited….
August 17th, 2006 at 4:19 pm
Here is some Applescript code you might like to integrate that looks for published calendars.
This script takes the approach of looking at all the calendars you publish, and will download changes (made by another) before opening up iCal. This way, you can use iCal’s publish on change feature.
If two iCals are both publishing at the same time, they will stomp each other, but for the every few days edit, this doesn’t result in collisions. Anyway, you might be able to make use of the plist navigation code to avoid having the determine the full path to calendar source, and use the AS choose item dialog instead.
property icalSupportFolder : (path to home folder as string) & "Library:Application Support:iCal:"
property nodesPlist : icalSupportFolder & "nodes.plist"
property sources : {}
property passwds : {}
on getValue(akey, keys, values)
if keys does not contain akey then return false
repeat with i from 1 to count of keys
if item i of keys = akey then return item i of values
end repeat
return false
end getValue
on getPW(source)
log “PW routine”
return my getValue(source, sources, passwds)
end getPW
–iCal should be closed to refresh
tell application “Finder”
if name of every process contains “iCal” then
tell application “iCal” to quit
end if
end tell
tell application “System Events”
–set nodesPlist to POSIX path of nodesPlist
set calendarList to property list items of property list item “List” of contents of property list file nodesPlist
set publishedCalendarList to {}
–set publishedCalendarNames to {}
repeat with i from 1 to count of calendarList
set pubData to property list items of property list item “Publishers” of item i of calendarList
if pubData ≠ {} then
–set end of publishedCalendarList to i
set end of publishedCalendarList to ((i as string) & ” : ” & value of property list item “PublishName” of item 1 of pubData)
end if
end repeat
end tell
August 17th, 2006 at 8:54 pm
Subversion has a webdav plugin for apache. Keeping your icals in version control is a good way not to lose anything.
August 18th, 2006 at 3:46 am
You may want to look at Conditional Get HTTP requests; if the file on the server hasn’t changed then you don’t need to download it, which is more efficient than downloading it and md5ing it.
August 25th, 2006 at 7:02 am
Thanks for this script!
I had to change one line. Instead of
$WGET -c –http-user=$LOGIN –http-password=$PASSWORD $WEBDAV -O $NEWCAL
I needed
$WGET -c –http-user=$LOGIN –http-passwd=$PASSWORD $WEBDAV -O $NEWCAL
October 22nd, 2006 at 2:01 pm
[...] permalink Geht wohl, mit viel Mühe [...]
November 10th, 2006 at 12:53 pm
[...] Über meine veränderten Arbeitsbedingungen, insbesondere die digitalen Einschnitte, habe ich bereits geschrieben. Und da web2.0 viel schöner ist als Windows 98 suche ich gerade nach Möglichkeiten, wie ich meine Informationen hier und zu Hause verfügbar haben kann. Der Google Calendar stimmt mich da erst mal recht hoffnungsvoll. Spätestens wenn Spanning Sync eine Software heraus gibt, die meinen iCal mit dem google-Kalender synchronisiert kann ich meine Termine auch ohne Handy verwalten. Zuvor hatte ich versucht, den Kalender über WebDAV mit einem eigenen Skript zu synchronisieren, da meine Dokumente schon auf einem WebDAV-Server zu Hause (Mac) und in der Schule (Windows) übers Netz verfügbar sind. Aber das war definitiv zu schwierig. tags:digital [...]
March 13th, 2007 at 5:52 pm
Thanks to your script, we’re now able to share the calendar of our work group — great!
Here a few short improvements:
Both in the shell script and in the do shell script instruction in the AppleScript, you can abbreviate your home directory using ~
Instead of command; if [ $? -eq 0 ]; then …, you can write if command; then
Furthermore, I do not understand why you use wget -c (continue download), as the script only tries to download the calendar file once.
December 20th, 2007 at 6:18 am
I would like to see a continuation of the topic
March 27th, 2009 at 7:14 am
Hi all,
I know the thread is quite old but the solution seems to work for me. Almost that is.
I made some changes because I have multiple calendars to sync and md5’s output differs from md5sum’s.
When I change an event on one mac the online .ics file gets updated. I close iCal, call the script from the 2nd mac. The output:
----------------------------/Users/******/Library/Application Support/iCal/Sources/******-******-******-******-******.calendar
Downloading calendar from WebDAV server…
/opt/local/bin/wget -c –http-user=****** –http-password=****** http://cal.******./***.ics -O caldownload.ics
–2009-03-27 11:21:28– http://cal.******./****.ics
Auflösen des Hostnamen »cal.******.*«…. **.*..*
Verbindungsaufbau zu cal.******.*|**.*..*|:80… verbunden.
HTTP Anforderung gesendet, warte auf Antwort… 200 OK
Länge: 142779 (139K) [text/calendar]
In »caldownload.ics« speichern.
100%[===========================================================================>] 142.779 259K/s in 0,5s
2009-03-27 11:21:28 (259 KB/s) – »cal_download.ics« gespeichert [142779/142779]
******.ics
Checking for ICS format…
END:VCALENDAR
Is 1398d4586067870fb39db9cc1dd7be1c = 035d54e17dbb254fbc18a5f5f94d7bb5?
Updating local ical…
Done! Phew, glad this is over.
The folder ~/Library/Application Support/iCal/Sources/******-******-******-******-******.calendar now contains an updated version of corestorage.ics and the backup corestorage.ics.old.
When I open corestorage.ics in my favorite editor (TextMate) I can find the event change I made on the other system. When I launch iCal the event is not updated.
In the folder ~/Library/Calendars I found more calendar data.
Could it be that Apple changed the location of the main iCal data storage? Am I updating in the wrong place?
Thanks for any hints on this one.
May 13th, 2009 at 3:47 pm
I noticed that these folders are no longer used in a long time. Actually, since 2007 in my case (leopard?). They are now stored in ~/Library/Calendars
May 13th, 2009 at 4:12 pm
And oh, besides that, every event is now an .ics on its own. Doesn’t work.
July 19th, 2009 at 12:12 am
[...] to it. Now i want to sync with the server… Most details I could find are outdated (i.e. Vitriol and Routing Tables Blog Archive Sharing, Syncing and editing iCal over WebDAV) with respect to syncing from the server. Any tips would be appreciated __________________ [...]