Ok, so it’s been an embarrassingly long time between posts. It’s a good thing I don’t pretend to be blogging for a living.
Anyway, these days I’m hacking on the Cyrus IMAP server for a living. This software isn’t much to write home about. It’s Open Source so you get to see all the ugly bits. It’s really quite old and crufty (there’s K&R C in there!) and mostly works. Mostly.
What I’m supposed to be doing is adding Conversations support – more about that in another post sometime. What I’m mostly doing is cleaning up amazing crufty code and writing unit tests to prove that I didn’t break anything. The process goes something like this:
- Oh, I need a function to parse a date/time string.
- Cool, here’s one.
- Oh…here’s another one…in a different file in a different directory…that only reads directly from the main IMAP protocol stream. No worries, we can split it up into a sensible pair, one of which reads a quoted string from the protocol stream into a buffer, another which converts the buffer to a time_t.
- Wait, they parse different formats. Because RFC822 and RFC3501 specify similar but not identical date/time formats. Well, whatever, they’re both necessary for RFC compliance.
- Ooh, one of them takes about a half-dozen different flags, let’s write a comment documenting their effects.
- Wait, most of the flag combinations make no sense. One combination results in two separate timezone offsets being applied to the result, the one specified in the date/time string itself, and also the server’s own timezone. WTF? Aha, there’s only two different sets of flags it’s called with…so change the function to take a boolean.
- Cool, this function has support for Military single-letter timezone names (e.g. ‘Z’ is UTC). Wait, it accepts ‘J’ as a timezone name, which it isn’t. Even better, this means it miscalculates timezones ‘K’ through ‘M’ which are now all off by one hour. Classy.
- Well I don’t trust it now…ah, it parses some hardcoded US timezone names, like EST, PDT etc. Oh but look, the Daylight Savings calculation moves one hour in the wrong direction. Wonderful.
- What? Here’s more date/time parsing code! This time it parses the RFC3339 date format (which is mostly the same as the ISO8601 format, and is arguably the most sensible one of them all). It’s opencoded in the middle of a function that parses imap:// URLs, of all things.
- Ok, I give up. I’m gonna fix it all up! Pull all the date/time parsing and generating code out into a new source file, lib/times.c, fix the names of the functions to be remotely sensible and consistent, enforce sensible and consistent return values (number of characters consumed or generated, or -1 on error), and write unit tests for the lot.
And that’s what I’ve spent so much time doing recently. So many ratholes, so little time.