Automatically generate AirPrint Avahi service files for CUPS printers

21 Nov 2010

Ataraxia Consulting

Last weekend I read Ryan Finnie’s excellent article about getting CUPS printers to work with AirPrint ( I got a bit angry at Ubuntu/avahi/CUPS/Apple regarding some silliness involving the APIs that are used by CUPS internally for DNSSD announcement (like the fact it’s broken in 10.04 and 10.10 because Apple changed APIs and the new API calls weren’t packaged (yet?)). So after I finished ranting to myself I created the service file and boom, I could print from my iPhone.


Sucks to have to create these .service files manually though, if only something could just talk to CUPS and spit out these files for me. So this weekend I decided to whip up a small script to do just that.

It’s a small python script that can talk to a CUPS server (by default the local socket) and write out some xml suitable for use with avahi. It doesn’t do much special, just grabs all configured printers that are marked shared and create files that when avahi exports them will make the printers visible from an iOS device. You are responsible to make sure your printer is configured properly in CUPS. You should make sure CUPS can send and print a test page, if it can’t do that it’s unlikely that the print you send it from your iOS device will work either. Your CUPS server should also have a working PDF filter, since most times that’s what the iOS device will send.

Without any options, it will communicate with your local CUPS instance (or that is to say, will do what ever the cups client library will do by default, there may be environment variables at play here), after it learns about each printer it will generate an xml file AirPrint-[name of printer in CUPS].service, putting this file somewhere where avahi knows to load it will automagically make the printer available to iOS devices (the directory in my experience is /etc/avahi/services). You can also specify -p [PREFIX] if you aren’t a fan of AirPrint-. There is also -d [TARGET DIRECTORY] if you wanted to specify the avahi services directory, if you supply this parameter all the xml files will be generated in that directory, otherwise they will be generated in the current working directory.

DNSSD has a limit of 255 characters for a txt-record entry, currently not all fields are verified for this, the one place where it is checked is the entry that generates the “pdl=” record, this is the hint record that specifies what content-types the printer will accept. There is an internal priority list (in the future you will be able to influence this) that keeps important content-types at the head and experimental/unnecessary ones out all together. The resulting entry is truncated to fit into 255 (without also creating malformed entries). If you’re curious to see what will be truncated make sure to run the script with the rather ugly –verbose option.

In the future (with proper motivation) I will add the other hint fields that include things like duplexing, but it wasn’t immediately obvious to me which CUPS printer attributes store that information in a consistent way.

It would also be trivial to take this script and instead of generating avahi service files directly, use a python binding for dnssd/avahi/bonjour to do the announcements directly (at least as a stop gap until CUPS >= 1.4 + Debian (and derivatives) get the packaging solidified [and add airprint announcments]).