208 lines
6.7 KiB
Plaintext
208 lines
6.7 KiB
Plaintext
|
#!/usr/bin/perl
|
||
|
# The above Perl path may vary on your system; fix it!!! -*- perl -*-
|
||
|
|
||
|
# dnssd - Search for network printers with the avahi-browse command
|
||
|
# (Zeroconf, DNS-SD)
|
||
|
|
||
|
# Printer discovery CUPS backend (like the SNMP backend)
|
||
|
# See also http://qa.mandriva.com/show_bug.cgi?id=21812
|
||
|
|
||
|
# Copyright 2007 Till Kamppeter <till.kamppeter@gmail.com>
|
||
|
#
|
||
|
# This program is free software; you can redistribute it and/or modify it
|
||
|
# under the terms of the GNU General Public License as published by the
|
||
|
# Free Software Foundation; either version 2 of the License, or (at your
|
||
|
# option) any later version.
|
||
|
#
|
||
|
# This program is distributed in the hope that it will be useful, but
|
||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||
|
# Public License for more details.
|
||
|
#
|
||
|
# You should have received a copy of the GNU General Public License
|
||
|
# along with this program; if not, write to the Free Software
|
||
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||
|
# USA.
|
||
|
|
||
|
# Usage:
|
||
|
#
|
||
|
# cp dnssd /usr/lib/cups/backend/
|
||
|
# chmod 755 /usr/lib/cups/backend/dnssd
|
||
|
# killall -HUP cupsd (or "/etc/init.d/cups restart", CUPS 1.1.x only)
|
||
|
# lpinfo -v (or use any printer setup tool)
|
||
|
|
||
|
#use strict;
|
||
|
|
||
|
$0 =~ m!^(.*)/([^/]+)\s*$!;
|
||
|
my $progname = ($2 || $0 || "dnssd");
|
||
|
my $progpath = ($1 || "/usr/lib/cups/backend");
|
||
|
|
||
|
if ($ARGV[0]){
|
||
|
die "This backend is only for printer discovery, not for actual printing.\n";
|
||
|
}
|
||
|
|
||
|
my $avahicmd = "avahi-browse -k -t -v -r -a 2> /dev/null";
|
||
|
|
||
|
# IPs which are for computers, consider their printer entries as queues
|
||
|
# set up with the local printing system (CUPS, LPD, Windows/Samba SMB, ...)
|
||
|
my @ipblacklist = ();
|
||
|
my $output;
|
||
|
my ($interface, $nettype, $ip, $host, $make, $model, $description, $cmd, $makemodel, $deviceid, $protocol, $port, $uriext, $uri);
|
||
|
|
||
|
open (AVAHI, "$avahicmd |") or die "Could not call \"$avahicmd\"\n";
|
||
|
while (my $line = <AVAHI>) {
|
||
|
chomp ($line);
|
||
|
if ($line =~ /^\s*=\s+(\S+)\s+(\S+)\s+(.*?)\s+(\S+)\s+(\S+)\s*$/) {
|
||
|
# New item
|
||
|
$interface = $1;
|
||
|
$nettype = $2;
|
||
|
my $itemname = $3;
|
||
|
my $protocolinfo = $4;
|
||
|
if ($protocolinfo =~ /_workstation/) {
|
||
|
$protocol = "computer";
|
||
|
} elsif ($protocolinfo =~ /_pdl-datastream/) {
|
||
|
$protocol = "socket";
|
||
|
} elsif ($protocolinfo =~ /_printer/) {
|
||
|
$protocol = "lpd";
|
||
|
} elsif ($protocolinfo =~ /_ipp/) {
|
||
|
$protocol = "ipp";
|
||
|
}
|
||
|
} elsif ($line =~ /^\s*hostname\s*=\s*\[([^\]]+)\]\s*$/) {
|
||
|
$host = $1;
|
||
|
$host =~ s/\.local\.?$//;
|
||
|
} elsif ($line =~ /^\s*address\s*=\s*\[([^\]]+)\]\s*$/) {
|
||
|
$ip = $1;
|
||
|
if ($protocol eq "computer") {
|
||
|
push (@ipblacklist, $ip);
|
||
|
$protocol = "";
|
||
|
}
|
||
|
} elsif ($line =~ /^\s*port\s*=\s*\[([^\]]+)\]\s*$/) {
|
||
|
$port = $1;
|
||
|
} elsif ($line =~ /^\s*txt\s*=\s*\[(.+)\]\s*$/) {
|
||
|
my $info = $1;
|
||
|
if ($protocol) {
|
||
|
my ($ty, $product, $pdls, $usb_MFG, $usb_MDL, $usb_DES, $usb_CMD) =
|
||
|
("", "", "", "", "", "", "");
|
||
|
while ($info =~ s/^\s*\"([^\"]+)\"\s*//) {
|
||
|
my $infoitem = $1;
|
||
|
if ($infoitem =~ /^([^=]*)=(.*)$/) {
|
||
|
my $field = $1;
|
||
|
my $content = $2;
|
||
|
if ($field eq "ty") {
|
||
|
$ty = $content;
|
||
|
} elsif ($field eq "product") {
|
||
|
$product = $content;
|
||
|
$product =~ s/^\((.*)\)$/$1/;
|
||
|
} elsif ($field eq "usb_MFG") {
|
||
|
$usb_MFG = $content;
|
||
|
} elsif ($field eq "usb_MDL") {
|
||
|
$usb_MDL = $content;
|
||
|
} elsif ($field eq "usb_DES") {
|
||
|
$usb_DES = $content;
|
||
|
} elsif ($field eq "usb_CMD") {
|
||
|
$usb_CMD = $content;
|
||
|
} elsif ($field eq "rp") {
|
||
|
$uriext = $content;
|
||
|
} elsif ($field eq "pdl") {
|
||
|
while ($content =~ s/^\s*([^\,]+?)\s*\,\s*//) {
|
||
|
my $i = $1;
|
||
|
if ($i =~ m!\b(postscript|ps)\b!i) {
|
||
|
$pdls .= "POSTSCRIPT,";
|
||
|
} elsif ($i =~ m!\b(pdf)\b!i) {
|
||
|
$pdls .= "PDF,";
|
||
|
} elsif ($i =~ m!\b(pcl6|pclxl|pxl)\b!i) {
|
||
|
$pdls .= "PCLXL,";
|
||
|
} elsif ($i =~ m!\b(pcl[345][ce]?|pcl)\b!i) {
|
||
|
$pdls .= "PCL,";
|
||
|
}
|
||
|
}
|
||
|
$pdls =~ s/\,$//;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
$usb_MDL ||= $ty;
|
||
|
$usb_DES ||= $product;
|
||
|
if ($usb_MFG) {
|
||
|
$make = $usb_MFG;
|
||
|
} elsif ($usb_DES =~ /^KONICA\s+MINOLTA\b/i) {
|
||
|
$make = "KONICA MINOLTA";
|
||
|
} elsif ($usb_DES) {
|
||
|
$usb_DES =~ /^\s*(\S*)\b/;
|
||
|
$make = $1;
|
||
|
}
|
||
|
$model = $usb_MDL;
|
||
|
if (!$model) {
|
||
|
$usb_DES =~ /^\s*\S*\s*(.*)$/;
|
||
|
$model = $1;
|
||
|
}
|
||
|
$usb_CMD ||= $pdls;
|
||
|
my $extra;
|
||
|
if ($protocol eq "socket") {
|
||
|
$uri = "socket://$ip:$port";
|
||
|
$extra = "Port $port";
|
||
|
} elsif ($protocol eq "lpd") {
|
||
|
$uri = "lpd://$ip" . ($uriext ? "/$uriext" : "");
|
||
|
$extra = ($uriext ? "Queue: $uriext" : "Default queue");
|
||
|
} elsif ($protocol eq "ipp") {
|
||
|
$uri = "ipp://$ip:$port" . ($uriext ? "/$uriext" : "");
|
||
|
$extra = ($uriext ? "Queue: $uriext" : "Default queue");
|
||
|
}
|
||
|
if ($make && $model) {
|
||
|
$make =~ s/Hewlett.?Packard/HP/i;
|
||
|
$make =~ s/Lexmark.?International/Lexmark/i;
|
||
|
$model =~ s/Hewlett.?Packard/HP/i;
|
||
|
$model =~ s/Lexmark.?International/Lexmark/i;
|
||
|
while ($model =~ s/^\s*$make\s*//i) {};
|
||
|
$makemodel = "$make $model";
|
||
|
} elsif ($usb_DES) {
|
||
|
$makemodel = $usb_DES;
|
||
|
} else {
|
||
|
$makemodel = "Unknown";
|
||
|
}
|
||
|
$deviceid = ($usb_MFG ? "MFG:$usb_MFG;" : "") .
|
||
|
($usb_MDL ? "MDL:$usb_MDL;" : "") .
|
||
|
($usb_DES ? "DES:$usb_DES;" : "") .
|
||
|
($usb_CMD ? "CMD:$usb_CMD;" : "");
|
||
|
$deviceid .= "CLS:PRINTER;" if $deviceid;
|
||
|
$output->{$ip}{$protocol}{$extra} =
|
||
|
"network $uri \"$makemodel\" \"$makemodel $ip ($extra)\" \"$deviceid\"\n";
|
||
|
($interface, $nettype, $ip, $host, $make, $model, $description, $cmd, $makemodel, $deviceid, $protocol, $port, $uriext, $uri) =
|
||
|
("", "", "", "", "", "", "", "", "", "", "", "", "", "");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
foreach my $ip (keys(%{$output})) {
|
||
|
next if member($ip, @ipblacklist);
|
||
|
if ($output->{$ip}{"socket"}) {
|
||
|
foreach my $extra (keys(%{$output->{$ip}{"socket"}})) {
|
||
|
if (keys(%{$output->{$ip}{"socket"}}) = 1) {
|
||
|
$output->{$ip}{"socket"}{$extra} =~
|
||
|
s/^(\s*\S*\s*\S*\s*\"[^\"]*\"\s*\"[^\"\(]*?)\s*\([^\)]*\)\s*(\"\s*.*)$/$1$2/;
|
||
|
}
|
||
|
print $output->{$ip}{"socket"}{$extra};
|
||
|
}
|
||
|
} elsif ($output->{$ip}{"lpd"}) {
|
||
|
foreach my $extra (keys(%{$output->{$ip}{"lpd"}})) {
|
||
|
if (keys(%{$output->{$ip}{"lpd"}}) = 1) {
|
||
|
$output->{$ip}{"lpd"}{$extra} =~
|
||
|
s/^(\s*\S*\s*\S*\s*\"[^\"]*\"\s*\"[^\"\(]*?)\s*\([^\)]*\)\s*(\"\s*.*)$/$1$2/;
|
||
|
}
|
||
|
print $output->{$ip}{"lpd"}{$extra};
|
||
|
}
|
||
|
} elsif ($output->{$ip}{"ipp"}) {
|
||
|
foreach my $extra (keys(%{$output->{$ip}{"ipp"}})) {
|
||
|
if (keys(%{$output->{$ip}{"ipp"}}) == 1) {
|
||
|
$output->{$ip}{"ipp"}{$extra} =~
|
||
|
s/^(\s*\S*\s*\S*\s*\"[^\"]*\"\s*\"[^\"]*?)\s*\([^\)]*\)\s*(\"\s*.*)$/$1$2/;
|
||
|
}
|
||
|
print $output->{$ip}{"ipp"}{$extra};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
exit 0;
|
||
|
|
||
|
# member( $a, @b ) returns 1 if $a is in @b, 0 otherwise.
|
||
|
sub member { my $e = shift; foreach (@_) { $e eq $_ and return 1 } 0 };
|