Calendrical machinations

The other day, I was searching around for information on how to integrate Google Calendar with iCal, and I came across something that makes me think I won’t need to mess with Google Calendar at all.

My problem is the two-computer problem. I have a desktop machine at work and a laptop I use at home and on the road. I often need info from the desktop when working at the laptop, particularly email, addresses, and calendar entries. The email issue has been solved by routing everything through GMail: at work I use Mail.app to pop mail from GMail and make a local copy, at home I access GMail directly. Addresses are not handled by anything so automatic; every so often I copy the desktop’s version of the ~/Library/Application Support/AddressBook folder to the laptop. This has worked out well enough because the AddressBook data doesn’t change very much or very quickly. And even when I find I don’t have certain contact data on my laptop, the data I need is almost always somewhere in an email.

Calendar data, on the other hand, changes often and is typically not to be found in an email. So I was looking into Google Calendar to see if I could use it sort of like I use GMail: a locally-stored copy on the desktop machine at work, with online access by the laptop. Unfortunately, there doesn’t seem to be a simple way to publish iCal calendars to Google Calendar. But I learned something about iCal’s publish-and-subscribe system that will solve my problem.

This hint on macosxhints.com showed me that iCal can subscribe to calendars using FTP. I had known that you can do this using WebDAV, which is also how you publish a calendar. In fact, I had asked my web host last year about adding WebDAV support so I could set up a publish-and-subscribe system between my two computers. They said they had no plans to add WebDAV, so I gave up. But now that I know iCal can subcribe (but not publish) via FTP, all I need to do is:

  1. set up an automated system for FTPing my work calendars to my host’s server;
  2. set my laptop’s iCal to subscribe to those calendars via FTP;
  3. profit!

Using the information from the hint, I figured out the correspondence between the calendar names on my desktop machine and the oddly-named folders in ~/Library/Application Support/iCal/Sources. In a nutshell, ~/Library/Application Support/iCal/Sources contains a folder for each of your calendars. But instead of having the same names as the calendars, these folders have long hexidecimal-looking names. Inside these folders is a file named corestorage.ics, which is where the data is, and a file named Info.plist, which contains the name of the calendar associated with that data. Weird, but reasonably easy to figure out.

I took this information, highjacked the FTP stuff out of my command-line screenshot utility, and the result is this Perl program.

#!/usr/bin/perl

use Net::FTP;

# Parameters
$user = "username";
$pass = "seekret";
$host = "ftp.myserver.com";
$ftpdir = "calendars";
$localdir = "$ENV{HOME}/Library/Application Support/iCal/Sources";
%calnames = (
  "AAAAAAAA-BBBB-CCCC-DDDD-222222222222.calendar" => "special-days.ics",
  "AAAAAAAA-BBBB-CCCC-DDDD-444444444444.calendar" => "family.ics",
  "AAAAAAAA-BBBB-CCCC-DDDD-666666666666.calendar" => "work.ics",
  "AAAAAAAA-BBBB-CCCC-DDDD-888888888888.calendar" => "home.ics",
  "AAAAAAAA-BBBB-CCCC-DDDD-AAAAAAAAAAAA.calendar" => "fed-holiday.ics"
);

# Have to quit iCal to make the calendars write out to disk.
$quitiCal = qq(tell application "iCal" to quit);
`osascript -e '$quitiCal'`;

# Open connection to ftp site.
$ftp = Net::FTP->new($host,Timeout=>240) 
          or die "Couldn't contact $host: $!";
$ftp->login($user, $pass);
$ftp->cwd($ftpdir);
$ftp->binary;

# Go to the localdir.
chdir($localdir) or die "Couldn't change to $localdir: $!";

# Copy the 'corestorage files in the localdir to the ftpdir, using
# the calendar name.
foreach $caldir (sort keys %calnames) {
  # print "$caldir => $calnames{$caldir}\n";
  chdir($caldir) or die "Couldn't change to $caldir: $!";
  $ftp->put("corestorage.ics", $calnames{$caldir});
  chdir("..");
}

$ftp->quit;

All the personal info has been changed, of course. The stuff that would have to be changed to work for you is in the #Parameters section.

The only oddball thing in the script is the call to quit iCal. Apparently, iCal doesn’t write out to the corestorage.ics file until it quits, so you have to quit iCal to make sure the corestorage.ics is up-to-date. iCal must keep changes in a temporary file while it’s running—I can’t believe it trusts your data to volatile RAM.

On the laptop, I subscribe to these calendars by choosing Subscribe… from the Calendar menu and entering, for example, ftp://ftp.myserver.com/calendars/work.ics in the sheet that drops out of the title bar. I then enter the necessary login information to make the FTP connection and I’m set. OS X’s Keychain system keeps track of the username and password, so the calendars will refresh without my having to login every time.

To complete the circle, I’ve created a calendar on the laptop called from-ibook, which I use when I need to enter an event while working on the laptop. This calendar gets FTPed to the same spot and the desktop at work subscribes to it. Since I want the work computer to have the canonical version of the calendar, I now have to do two things:

  1. when I get to work and see items in the from-ibook category (colored green), copy them to the work or home categories, as appropriate;
  2. when I’m back at the laptop, delete the items from from-ibook because they’re now in another category.

These last two steps are obvious candidates for automation via AppleScript, but since I hate AppleScript, I’m not going to do it unless I find myself moving items often.

(Calendar geeks will recognize the pun in the post’s title.)

Tags: