Neary two years ago I had a go at making it work with Leopard, and in the meantime a few things changed - I upgraded my home server setup to Snow Leopard, iOS is now in its sixth revision, and I also changed printers.
AirPrint is not something I need to use often (if at all), but it’s handy enough for me to want it to work. It’s basically a set of tweaked CUPS filters and Bonjour announcements, and it’s somewhat aggravating that Apple can’t seem to bother to retrofit it to older Macs when it’s an altogether trivial hack.
Picking up where we left off earlier, to get this working on Snow Leopard I first added the “new” MIME types to CUPS (inspired by this post, which was my first and last stop while investigating the status quo):
sudo launchctl stop org.cups.cupsd sudo sh -c "echo 'image/urf urf string(0,UNIRAST<00>)' > /usr/share/cups/mime/airprint.types" sudo sh -c "echo 'image/urf application/pdf 100 cgpdftoraster' > /usr/share/cups/mime/airprint.convs" sudo launchctl start org.cups.cupsd
However, I’m pretty sure this isn’t actually used, since I’ve yet to see my iOS devices send
URF data to the printer - and that because since there is no apparent way to tweak the way CUPS registers printers in Bonjour, I set up a duplicate service with the
URF record set to
none like I did earlier - but this time, I whipped up the requisite Python script:
from subprocess import Popen, PIPE from signal import alarm, signal, SIGALRM class Alarm(Exception): pass def handler(signum, frame): # map the signal to an exception raise Alarm def dnssd(params, pattern='local.', timeout=3): h = Popen('dns-sd %s' % params, shell=True, stdout=PIPE) # set up a timeout if timeout: signal(SIGALRM, handler) alarm(timeout) result =  try: # readline will block when dns-sd enters its loop while True: line = h.stdout.readline() if pattern in line: result.append(line) except Alarm: h.kill() return result # grab all instances of _ipp._tcp services printers = map( lambda entry: entry.split('_ipp._tcp.').strip(), dnssd('-B _ipp._tcp.', 'local.', 3) ) # tack on 'URF=none' to each service info entries =  for p in printers: entries.extend(map( lambda record: (p.split("@").split(' '), record.strip() + ' URF=none'), dnssd('-L "%s" _ipp' % p, 'txtvers', 1) )) # now advertise the first entry (advertising more than one would require # something like multiprocessing.Pool() or just plain exec(), and I have # just the one printer...) dnssd('-R "%s AirPrint" _ipp._tcp,_universal local. 631 %s' % entries, timeout=0)
This is somewhat of a hack since
dns-sd isn’t really supposed to be used this way - but it’s simpler and easier to understand than my attempt at doing the same with
I’ve also tinkered with the notion of setting up an AirPrint renderer/redirector on a Raspberry Pi, and will probably end up doing that later - it should be pretty much the same thing, really, except you’ll want to look at airprint-generate to make it easier to set up the Bonjour announcements.