Sunday, November 11, 2012

Setting up an AirPrint server on Linux

I recently had a need to set up printing from an iPad3 and iPhone and hoped to use my existing Lexmark x4650 which serves my home network.

Now, there are a few things to remember about the architecture of iOS printing. iOS devices require that a printer has to support AirPrint which uses Multicast DNS (mDNS). mDNS is a broadcast protocol (by default on port 5353 and using UDP in the same way that DNS does) that the airprint service uses to advertise that the printer is available (and on what port the service is listening on).

Unfortunately for me, the Lexmark x4650 does not support AirPrint, so an alternative mechanism needs to be used to deliver this requirement. Now, since I'm a linux user (Lubuntu is my distro of choice at the moment), Linux printing uses CUPS as it's print manager architecture which listens on port 631, by default, so you need some mechanism of implementing the listener such that it accepts AirPrint traffic whilst interacting with CUPS. So, in steps avahi, which is the standard way of implementing this listener.

So, firstly, I got the printer setup on Linux. Whilst it's not supported out of the box (this is handled by the openPrinting.org initiative), fortunately, Lexmark do offer Linux drivers.

Once the printer was setup (and hence CUPS was setup), then all that was needed was to configure avahi. So, a quick peruse of /etc/avahi/services shows that you need to define a .service file, which I manually created with the following XML :
<?xml version="1.0" ?>
<!DOCTYPE service-group  SYSTEM 'avahi-service.dtd'>
<service-group>
  <name replace-wildcards="yes">
AirPrint Lexmark-3600-4600-Series @ %h</name>
  <service>
    <type>_ipp._tcp</type>
    <subtype>_universal._sub._ipp._tcp</subtype>
    <port>631</port>
    <txt-record>txtvers=1</txt-record>
    <txt-record>qtotal=1</txt-record>
    <txt-record>Transparent=T</txt-record>
    <txt-record>URF=none</txt-record>
    <txt-record>rp=printers/Lexmark-3600-4600-Series</txt-record>   
    <txt-record>note=Lexmark 3600-4600 Series</txt-record>
    <txt-record>product=(GPL Ghostscript)</txt-record>
    <txt-record>printer-state=3</txt-record>
    <txt-record>printer-type=0x2d00c</txt-record>
    <txt-record>pdl=image/urf,application/octet-stream,
application/pdf,application/postscript,application/vnd.cups-raster,
image/gif,image/jpeg,image/png,image/tiff,
text/html,text/plain,application/vnd.adobe-reader-postscript,
application/vnd.cups-pdf</txt-record>
 </service>
</service-group>
Notice, that I had to add the image/urf MIME type to the PDL txt-record entry.

Then, you have to tell CUPS to map the image/urf MIME type to the same as a PDF entry. You do this via creating two files in /usr/share/cups/mime. I called mine apple.types which contained the following :
image/urf urf (0,UNIRAST)
and then a local.convs file which contains the following :
image/urf application/vnd.cups-postscript 66 pdftops
Once this was done then the iPhone/iPad successfully detected the printer (when scanning for an AirPrint printer) and traffic sent to the AirPrint service was placed onto the relevant CUPS print queue for the x4650.

There were, of course, a few false starts and for future reference it is important to note that CUPS error logs are contained in /var/log/cups and it is also important to realise that since mDNS and CUPS are in play, you need to ensure that your firewall / iptables setup allows port 5353 and 631 open for this to work as well.

No comments: