2 # Functions for CUPS printer drivers
4 $webmin_windows_driver = 0;
5 $cups_ppd_dir = "/etc/cups/ppd";
6 $lpoptions = &has_command("lpoptions.cups") ? "lpoptions.cups" : "lpoptions";
8 # is_windows_driver(path, &printer)
9 # Returns the server, share, username, password, workgroup, program
10 # if path is a webmin windows driver
13 if ($_[1]->{'dev'} =~ /^smb:\/\/(\S*):(\S*)\@(\S*)\/(\S*)\/(\S*)$/) {
14 return { 'user' => $1,
21 elsif ($_[1]->{'dev'} =~ /^smb:\/\/(\S*):(\S*)\@(\S*)\/(\S*)$/) {
22 return { 'user' => $1,
28 elsif ($_[1]->{'dev'} =~ /^smb:\/\/(\S*)\/(\S*)\/(\S*)$/) {
29 return { 'workgroup' => $1,
34 elsif ($_[1]->{'dev'} =~ /^smb:\/\/(\S*)\/(\S*)$/) {
35 return { 'server' => $1,
44 # is_driver(path, &printer)
45 # Returns the driver name if some path is a CUPS driver, or undef
48 if (!$_[0] || !-r $_[0]) {
50 'desc' => $text{'cups_none'} };
52 local $ppd = &parse_cups_ppd($_[0]);
53 if ($ppd->{'NickName'}) {
54 # Looks like a CUPS PPD file!
56 'manuf' => $ppd->{'Manufacturer'},
57 'model' => $ppd->{'ModelName'},
58 'nick' => $ppd->{'NickName'},
59 'desc' => "$ppd->{'Manufacturer'} $ppd->{'ModelName'}" };
62 # Some other kind of interface file
69 # create_windows_driver(&printer, &driver)
70 sub create_windows_driver
72 if ($_[1]->{'workgroup'} && $_[1]->{'user'}) {
73 $_[0]->{'dev'} = "smb://$_[1]->{'user'}:$_[1]->{'pass'}\@$_[1]->{'workgroup'}/$_[1]->{'server'}/$_[1]->{'share'}";
75 elsif ($_[1]->{'workgroup'}) {
76 $_[0]->{'dev'} = "smb://$_[1]->{'workgroup'}/$_[1]->{'server'}/$_[1]->{'share'}";
78 elsif ($_[1]->{'user'}) {
79 $_[0]->{'dev'} = "smb://$_[1]->{'user'}:$_[1]->{'pass'}\@$_[1]->{'server'}/$_[1]->{'share'}";
82 $_[0]->{'dev'} = "smb://$_[1]->{'server'}/$_[1]->{'share'}";
84 return $_[1]->{'program'};
87 # create_driver(&printer, &driver)
90 local $drv = "$cups_ppd_dir/$_[0]->{'name'}.ppd";
91 undef($cups_driver_options);
92 if ($_[1]->{'mode'} == 0) {
96 elsif ($_[1]->{'mode'} == 2) {
98 return $_[1]->{'file'};
101 # Copy the driver into place
102 if ($_[1]->{'ppd'} =~ /\.gz$/) {
103 &system_logged("gunzip -c ".quotemeta($_[1]->{'ppd'}).
104 " >".quotemeta($drv));
107 ©_source_dest($_[1]->{'ppd'}, $drv);
110 $cups_driver_options = $_[1]->{'opts'}; # for modify_printer
115 # delete_driver(name)
118 &unlink_file("$cups_ppd_dir/$_[0].ppd");
121 # driver_input(&printer, &driver)
124 printf "<tr> <td><input type=radio name=mode value=0 %s> %s</td>\n",
125 $_[1]->{'mode'} == 0 ? 'checked' : '', $text{'cups_none'};
126 print "<td>($text{'cups_nonemsg'})</td> </tr>\n";
127 printf "<tr> <td><input type=radio name=mode value=2 %s> %s</td>",
128 $_[1]->{'mode'} == 2 ? 'checked' : '', $text{'cups_prog'};
129 printf "<td><input name=program size=40 value='%s'></td> </tr>\n",
130 $_[1]->{'mode'} == 2 ? $_[0]->{'iface'} : '';
132 # Display all the CUPS drivers
133 printf "<tr> <td valign=top><input type=radio name=mode value=1 %s> %s</td>\n",
134 $_[1]->{'mode'} == 1 ? 'checked' : '', $text{'cups_driver'};
135 local (@ppds, $d, $f, $ppd, %cache, $outofdate, @files, %donefile);
136 local $findver = &backquote_command("find --version 2>&1", 1);
137 local $flag = $findver =~ /GNU\s+find\s+version\s+([0-9\.]+)/i && $1 >= 4.2 ?
139 foreach my $mp (split(/\s+/, $config{'model_path'})) {
140 &open_execute_command(FIND, "find $flag ".quotemeta($mp).
141 " -type f -print", 1, 1);
144 next if (/\.xml$/); # Ignore XML PPD sources
146 next if ($donefile{$1}++);
151 &read_file("$module_config_directory/ppd-cache", \%cache);
152 foreach $f (@files) {
153 if (!defined($cache{$f})) {
158 if ($outofdate || scalar(keys %cache) != scalar(@files)) {
159 # Cache is out of date
162 foreach $f (@files) {
163 local $ppd = &parse_cups_ppd($f);
164 local $nn = $ppd->{'NickName'};
165 $cache{$f} = $donecache{$nn} ? "duplicate" : $ppd->{'NickName'};
168 &write_file("$module_config_directory/ppd-cache", \%cache);
171 print "<td><select name=ppd size=10>\n";
172 foreach $f (sort { $cache{$a} cmp $cache{$b} } keys %cache) {
173 if ($cache{$f} && $cache{$f} ne "duplicate" &&
174 !$done{$cache{$f}}++) {
175 printf "<option value=%s %s>%s\n",
176 $f, $_[1]->{'nick'} eq $cache{$f} ? 'selected' : '',
178 $currppd = $f if ($_[1]->{'nick'} eq $cache{$f});
183 # Display driver option inputs
185 local $ppd = &parse_cups_ppd($currppd);
186 print "<br><b>",&text('cups_opts', $ppd->{'NickName'}),
188 open(OPTS, "$lpoptions -p '$_[0]->{'name'}' -l 2>/dev/null |");
190 if (/^(\S+)\/([^:]+):\s*(.*)/ && $1 ne "PageRegion") {
191 print "<tr>\n" if ($i%2 == 0);
194 local @opts = split(/\s+/, $3);
195 print "<td><b>$disp:</b></td>\n";
196 print "<td><select name=ppd_$code>\n";
198 local $sel = ($o =~ s/^\*//);
199 printf "<option value='%s' %s>%s\n",
200 $o, $sel ? "selected" : "",
201 $ppd->{$code}->{$o} ?
202 $ppd->{$code}->{$o} : $o;
204 print "</select></td>\n";
205 print "<tr>\n" if ($i%2 == 1);
212 print "</td> </tr>\n";
217 # Parse driver selection from %in and return a driver structure
220 if ($in{'mode'} == 0) {
221 return { 'mode' => 0 };
223 elsif ($in{'mode'} == 2) {
224 $in{'program'} =~ /^(\S+)/ && -x $1 ||
225 &error(&text('cups_eprog', $in{'program'}));
226 return { 'mode' => 2,
227 'file' => $in{'program'} };
229 elsif ($in{'mode'} == 1) {
230 # CUPS printer driver
231 local $ppd = &parse_cups_ppd($in{'ppd'});
232 local $rv = { 'mode' => 1,
234 'nick' => $ppd->{'NickName'},
235 'manuf' => $ppd->{'Manufacturer'},
236 'model' => $ppd->{'ModelName'} };
237 foreach $i (keys %in) {
238 $rv->{'opts'}->{$1} = $in{$i} if ($i =~ /^ppd_(.*)$/);