Eigenes CUPS Backend schreiben#
Wer CUPS nicht kennt oder allgemeinere Infos dazu sucht, findet unter DruckenMitCUPS weitere Informationen.
CUPS ist ein sehr stark modularisiertes Drucksystem. Dabei gibt es für den eigentlichen Ausdruck, d.h. den Zugriff auf die Hardware oder auch das Netzwerk die sogenannten backends. Diese sind sozusagen Hardware- und Schnittstellentreiber. Falls man mit Druckjobs ausgefallene Sachen machen will, sind diese backends ein guter Ansatzpunkt. So kann man über die CUPS-Homepage z.B. Links zu Backends finden, die einen Druckbefehl per ssh auf einem fernen Rechner ausführen, oder die eine Mail aus dem Druckjob generieren.
Da ich selber ein spezielles Problem hatte, habe ich beschlossen, ein solches Backend selbst zu schreiben. Nach einigen Tücken war das Ganze im Prinzip gar kein Problem.
Was ist ein backend?#
Ein backend ist ein Shell-Programm (kann ein Executable sein, kann aber auch ein Shell-Script oder ein Perl-Programm sein). Wie dieses auszusehen hat, erfährt man auf der CUPS-Homepage im Software Programmers Manual, aber auch im Download-Bereich sollte man sich umsehen und z.B. das ssh-backend (ein Shell-Script) und das mailto-backend (in Python) ansehen.
Es gibt zwei Möglichkeiten, wie CUPS das backend aufruft:
Beim Serverstart wird das Programm ohne Parameter aufgerufen. Es kann daraufhin zeilenweise Informationen über verfügbare Drucker ausgeben. Hierbei kann es sich um "fertige" Drucker-URIs handeln, wenn eine komplette URI der Form backend:/pfad angegeben wird oder aber auch um ein Template, wenn nur backend angegeben wird. Ich demonstriere unten beides, was dazu führt, daß ein Drucker in der CUPS-Oberfläche direkt angewählt wird (Mail an root), während bei der anderen Auswahl erst noch eine URI (Mailadresse) eingegeben werden kann.
Beim Ausdruck werden dem Programm 5 oder 6 Parameter übergeben, die Informationen über den Druckjob enthalten. Darüberhinaus gibt es noch einige interessante Umgebungsvariablen, die man benutzen kann (z.B. für die Device-URI).
Installation#
Selbstgeschriebene Backends werden einfach in das Verzeichnis für Backends (bei Debian /usr/lib/cups/backend) kopiert. Es ist darauf zu achten, das die Datei ausführbar ist (ggf. chmod a+x name) und fertig!
Mein eigenes Backend#
Zum Testen habe ich ein Backend mail geschrieben. Man kann eine URI der Form "mail:/tbayen@mailserver" angeben und bekommt die Druckjobs als Mail zugestellt. Ich habe bisher als Druckertreiber "raw" eingestellt und bekomme die Druckdateien dadurch genauso zugesandt, wie der Client sie abschickt. Es dürfte allerdings auch möglich sein, einen Postscript-Treiber auszuwählen und so immer Postscript zugeschickt zu bekommen, das man dann im Mail-Programm nur noch anzuklicken braucht, um es anzuzeigen.
Besonderes zu meinem Quelltext werde ich hier kurz fassen, da ich versucht habe, die Dokumentation in den Quelltext zu packen. Also RTFS! Übrigens ist der Code sicher auch interessant zum Thema "Mailversand in Perl". Die längste Arbeit war nämlich, den Versand des Druckjobs als Attachment richtig hinzubekommen. -- ThomasBayen
Source#
#!/usr/bin/perl use strict; use warnings; use FileHandle; use MIME::Entity; # CUPS-Backend, um aus einem Druckauftrag eine Mail zu generieren. # Die Device-URI muss die Form # # mail:/user@computer.domain # # haben. Alles andere geht dann von selbst :-) Ein Device für den # Versand an root@localhost wird dem Benutzer bei der Einrichtung # schon vorgegeben. # benötigt Debian-Paket libmime-perl unless(@ARGV){ # Wird kein Parameter angegeben, will CUPS nur Infos über # angeschlossene Drucker. Die sind Zeilenweise in der Form # class uri model description # class: file, direct, serial, network print 'network mail "Unknown" "EMail-Address Mailer"',"\n"; print 'network mail:/root@localhost "Unknown" "Mail to root"',"\n"; exit; } # Jetzt extrahiere ich die Parameter, die für mich interessant sind. # Entgegen der Dokumentation gibts nur 5-6 statt 6-7 Parameter # (printer als erstes wird nicht angegeben) if($#ARGV<4 or $#ARGV>5){ print STDERR "ERROR: mail job-id user title copies options [file]\n"; exit 1; } my($job,$user,$title,$copies,$options,$filename)=@ARGV; my($deviceuri)=($ENV{DEVICE_URI} or ''); my($email)=($deviceuri=~m!^mail:/(.*)$!); # Druckdaten lesen und MIME-Type feststellen: my($file,$type); if($filename){ $type=`file -bi $filename`; open $file, "<$filename"; }else{ $file=*STDIN; $type='application/octet-stream'; } local $/; # slurp mode my $text=<$file>; # Mail erzeugen: my $mail=MIME::Entity->build( From =>"CUPS mailer ($user)", To =>$email, Subject=>"CUPS printjob '$title'", # Mail hat attachments und bestsht daher aus zwei Teilen: Type =>'multipart/mixed', ); $mail->attach(Data=><<"EOT"); Hello $email, this mail contains a printjob. It was send to you from the CUPS mail-backend. Device-URI.......: $deviceuri Job-ID...........: $job Sending User.....: $user Documenttitle....: $title Number of Copies.: $copies MIME-Type........: $type CUPS-backend 'mail' written by Thomas Bayen. EOT $mail->attach( Data =>$text, Type =>$type, # Druckjob wird nicht "inline" angezeigt, sondern immer als Attachment: Disposition=>'attachment', # Encoding, damit Sonderzeichen und Binärdateien nicht kaputt gehen: # Encoding =>'quoted-printable', # hängt sich leider weg!?! Encoding =>'base64', # geht aber auch ); $mail->send; # So gehts auch: #open PIPE,"|sendmail -t"; #print PIPE $mail->stringify; #close PIPE; exit 0;