Tom Insam

Another day, another python-daap release. Version 0.6 allows you to connect to shares requiring a password, and fixes some problems with the source tarball. However, there are still outstanding licensing issues that may entail an annoying change to the library in the future.

First a brief bit of history. Since version 4.2 iTunes has required incoming DAAP client requests to be signed with a hash of their parameters. In iTunes 4.2, this was signed using md5. In iTunes 4.5, this was changed to a slightly modified version of md5 with some internal numbers jiggered, presumably just to annoy me. In iTunes 7, the hash was changed again, and no-one has since reverse-engineered the new system, so no open-source DAAP clients can currently talk to the most recent version of iTunes. This is clearly the intent of the hash - it serves no other useful purpose, it exists only to prevent clients other than iTunes talking to music shares, presumably to enforce the restrictions on shared music.

PythonDaap can talk to all versions of iTunes <7, because I include in the source a modified version of the md5 digest algorithm that was reverse-engineered by David Hammerton. For the most recent version of iTunes, however, you're just out of luck. There are various people working on reverse-engineering this one but it's clearly a hopeless battle (it's far easier for Apple to come up with another hash than it is for anyone else to reverse-engineer it), and not one I have any interest in being involved with.

To complicate this more, the MD5 implementation I based my version on is the 'RSA Data Security, Inc. MD5 Message-Digest Algorithm', which is licensed under an annoyingly non-LGPL-compatible license (I'm required to refer to it as the 'RSA Data Security, Inc. MD5 Message-Digest Algorithm', for instance). Thus my ability to legally distribute the source of PythonDaap is in question. I see only 2 reasonable ways out for me:

  • I could port the code to use a library with a more friendly license - OpenSSL for instance. But that's a bunch of work (I didn't even do most of the work for the current hasher - I just ported the changes mode in Digest::MD5::M4p) and doesn't help the iTunes 7 problem.

  • I could just rip out the code completely, and only support iTunes servers before version 4 (and open source servers). This approach appeals to me more - I assume that most people are using recent versions of iTunes, so all the users of PythonDaap must be using open source servers. Many of these are far better servers than iTunes itself - they allow any number of connections, for instance, unlike iTunes and its ridiculous restrictions.

I consider it a real shame that the open source community has embraced a protocol that neither works with the most recent version of the software that it was reverse engineered from, nor is actually particularly well-designed or easy to use. There are plenty of open source server implementations of DAAP, and iTunes can talk to all of them just fine, but no open source clients can talk to iTunes. That developers are essentially supporting Apple in this by producing servers for a protocol that they're not able to write clients for is annoying.

More annoying is that, at the same time as being restricted by the closed protocol, I'm having to deal with problems caused by the fact that not all of my code is open enough. Yay.

The first XMLRPC blog API was the Blogger API which was very limited - you could create and edit very simple representations of posts. This was extended by both Movable Type and MetaWeblog, adding more complicated post types (you could set titles, keywords categories, etc) and the ability to get a list of posts available on the server. All of these APIs have their own namespaces, their own variable name prefixes, and varying support from clients. An example

  • metaWeblog.getCategories ( MetaWeblog API )

    metaWeblog.getCategories (blogid, username, password) returns struct

    The struct returned contains one struct for each category,
    containing the following elements: description, htmlUrl and rssUrl.

  • mt.getCategoryList ( Movabletype API )

    Description: Returns a list of all categories defined in the weblog.

    Parameters: String blogid, String username, String password

    Return value: on success, an array of structs containing String
    categoryId and String categoryName; on failure, fault.

Because you don't know which clients will be making which calls, you need to implement both. Further, the MetaWeblog API doesn't support post excerpts or extended content, but the MovableType API extends certain MetaWeblog calls with extra parameters to get and set these properties.

Essentially, if you have a blog that supports excerpts, keywords - anything other than posts with a title and content - then you need to implement all of the APIs. Then you find that some clients have arbitrarily decided that the blogid parameter must be an integer, despite the specs explicitly giving it a 'String' type.

It all works in the end, though.

This post has been spillover from a post on the Zimki blog about implementing the MetaWeblog API on Zimki. As the Zimki blog has a very simple post structure at the moment (just titles and content right now, although annoyingly we use a markup engine that no GUI client understands) I could get away with a nice basic implementation of just the core MetaWeblog API, and so a rant about the complexity of the APIs didn't really seem to fit there. Having written it, though, I felt it should go somewhere, and I did run into all these issues writing the MetaWeblog server.

I've released another version of PythonDaap, with trivial changes suggested by Aren Olson to return more metadata. Nothing particularly special, but that doesn't mean I can't make a release. Find it here.

I'm finding E4X to be one of those weird technologies that is alternately utterly wonderful and incredibly irritating. The ability to treat XML data as any other JavaScript data structure allows very fast app development and messing around, but every so often I find myself amazed at how awful the syntax is.

Today's irritation is about E4X attributes.

// a perfectly normal E4X object.
var myXML = <xml foo="bar">content</xml>;

// the attribute with value 'bar'
var myAttribute = myXML.@foo;

Easy. I love this stuff. Unfortunately, Zimki, my company's product, uses uneval to store complex objects, and the myAttribute variable there would count. uneval won't produce JSON but it does produce a string that, when run through eval, will probably produce the original data structure, and we store that string in a database to store object.

Not so for E4X nodes. Playing in the SpiderMonkey JS console,

js> uneval( myXML );
<xml foo="bar">content</xml>

js> uneval( myAttribute );

The first one is fine. That string will eval nicely back to the original E4X object. But the 'bar' there isn't valid JavaScript - eval won't restore the original object. In fact, had the original XML been something like:

<xml foo="delete_all_zimki_data()">bar</xml>

and we'd tried to use eval/uneval to store this XML, we'd have executed the attribute as JavaScript. Ick.

Unusually, Rhino handles this much better (normally I find Rhino lags in features..):

js> uneval( myAttribute );

Not really an attribute node any more, but at least it's valid JavaScript and won't destroy my server.

I don't even have a good solution for this. Right now I'm fudging E4X nodes in the storage engine, but I really feel that attribute nodes should uneval to something a little more sensible. Perhaps I'll be able to produce a patch to SpiderMonkey, if I have time..

I'm experimenting with a simple source code browser for Right now it's trivial - just a list of folders and links to files, but what I'm aiming for is pages showing the check-in history of various folders, when they were last changed, etc - essentially, the sort of boring stuff I'd get for free were I to use svnweb or trac or something.

As usual, though, that's not the point. I'd hate to have a web site that consisted of several different apps, written in different languages, needing hundreds of different apache modules, and all looking different - or needing different templates if I wanted to give them similar appearances. I'm not very good at design and building templates, so as a crazy insane developer, it's easier for me to write a subversion browser than it would be to bully trac into looking the way I want it.

So, the pysvn bindings - Python bindings to the subversion client library. They're lovely.

import pysvn
client = pysvn.Client()
projects ="")
for project in projects:
    print " * %s"

The logic behind the pages under /source isn't much more complex than that. There's no caching, I don't have to have a local checkout, and it's easily fast enough for a little website like this. The (fairly sparse) docs don't make it sufficiently clear, to my mind, that you can point the client at a remote repository instead of a local checkout, but you can.

Another trick (hack) I use is providing a 'short name' method to the directory entry objects. I pass the objects returned from the ls call directly to the django template, but you're not allowed to do anything clever in template space (the templates are touched by those designer people - can't trust 'em). To make it easier to print a human-readable name for the entries, I poke a short method into their namespace:

def short_name(self):
    offset ='/') + 1

PysvnDirent.short = short_name

Then the template needs a simple

<h2>files here</h2>

Evil. I'm clearly still too much of a perl programmer...

I have a lovely shiny office MacBook Pro sitting in front of me, and in the
middle of the top of the screen is this little annoying black square. It's an
iSight camera, and it can always see me.

It's annoying for two reasons. Firstly, it can always see me. There's a little
light to tell you that it's on, but it's perfectly capable of blipping on
briefly without you noticing. But mostly it's annoying because I hate
the thought of such a high-tech piece of technology just going to waste up there.

I really have no real use for this thing at all - I don't obsessively
catalogue my book collection
, I don't hold
frequent multi-person videoconference
, and I already have a
camera. I've also seen enough PhotoBooth
to last me my ENTIRE LIFE.
But merely having no good reason isn't a good enough reason to stop me, so I
came up with a use for it.

DuckCall is an application that runs in
the background, and takes a picture of you every 30 seconds using the iSight.
Then it'll set this picture to be your iChat or Adium 'status picture' thing -
the little picture of your head that other people see in their contact lists.
Setting away messages is so web1.0 - when I'm not at my computer, you know it,
because you can't see me. It'll also try to be smart - it won't do
anything if neither app is running, for instance.

Naturally, it's not perfect. For the Adium stuff to work, you need to be using
a recentish beta - the ones with the
single buddy icon shared between services. And it has a nice little
todo list, like all my projects.

The biggest thing wrong with it, though, is the Frankenstein nature of the thing. I write my crazy application prototypes in PyObjC because it's very easy to get something working. But there are no Cocoa bindings for reading from the iSight (why??) so I shell out to an external tool and save a file from the iSight to disk. Then I use AppleScript to load the file from disk and set the icon of either of the IM apps that happen to be running (or both, I guess, if you're weird). Using Python as the wrapper makes the app about 3 megabytes larger than it really should be. If someone wants to re-implement it in Objective C, that would be good.. :-)

Weirdy, I'm not sure if I like the philosophy of the app. I keep getting scared that it'll take photos of me at bad times. Given my stated reluctance to publicise my life it's odd that I even considered writing this thing. I comfort myself with the thought that no matter how stupid I look in this photo, it'll be gone in 30 seconds, and most people will never see it...

Get it here and tell me what you think..

Flame 0.2.2

A very minor release of Flame - we were too aggressive in de-duping the service list. It's possible to have more than one service with the same port an IP address, if they have different names. Thanks to Bruce Walker for the bug report.