Handle hostnames with upper-case letters
[webmin.git] / lpadmin / caldera-driver.pl
1 # caldera-driver.pl
2 # Functions for printer drivers as generated by COAS
3
4 %paper_sizes = ( 'a4', 'A4',
5                  'a3', 'A3',
6                  'a5', 'A5',
7                  'letter', 'US Letter',
8                  'legal', 'Legal',
9                  'ledger', 'Ledger' );
10 $driver_dir = "/etc/sysconfig/printers";
11 $base_driver = "/usr/libexec/printers/genericfilter";
12 open(BASE, $base_driver);
13 $base_driver_text = join(<BASE>);
14 close(BASE);
15 $webmin_windows_driver = 1;
16
17 # is_windows_driver(path)
18 # Returns the server, share, username, password, workgroup, program
19 # if path is a webmin windows driver
20 sub is_windows_driver
21 {
22 return &is_webmin_windows_driver(@_);
23 }
24
25 # is_driver(path, &printer)
26 # Returns the driver name and dpi if some path is a webmin driver, or undef
27 sub is_driver
28 {
29 if (!$_[0]) {
30         return { 'mode' => 0,
31                  'desc' => "$text{'caldera_none'}" };
32         }
33 open(DRV, $_[0]);
34 local @lines = <DRV>;
35 close(DRV);
36 local %conf;
37 if ($lines[1] =~ /^source ($driver_dir\/\S+)/) {
38         # Looks like a 2.3 caldera driver! Read the sysconfig file
39         &read_env_file($1, \%conf);
40         if ($conf{'GSDEVICE'} eq 'NET' || $conf{'GSDEVICE'} eq 'RAW') {
41                 # Driver isn't even used
42                 return { 'mode' => 0,
43                          'desc' => 'None' };
44                 }
45         elsif ($conf{'GSDEVICE'} eq 'uniprint') {
46                 # Uniprint driver
47                 foreach $u (&list_uniprint()) {
48                         $desc = $u->[1] if ($u->[0] eq $conf{'UPP'});
49                         }
50                 $desc =~ s/,.*$//g;
51                 return { 'mode' => 3,
52                          'upp' => $conf{'UPP'},
53                          'paper' => $conf{'PAPERSIZE'},
54                          'double' => lc($conf{'DOUBLEPAGE'}),
55                          'eof' => lc($conf{'SENDEOF'}),
56                          'desc' => $desc ? $desc : $conf{'UPP'} };
57                 }
58         else {
59                 # A caldera printer driver
60                 open(COAS, $config{'coas_printers'});
61                 local $plist = &parse_coas(COAS);
62                 close(COAS);
63                 local ($prn, $p);
64                 foreach $p (values %$plist) {
65                         $prn = $p
66                                 if ($p->{'type'}->{'0'} eq $conf{'GSDEVICE'} &&
67                                     !$desc);
68                         }
69                 return { 'mode' => 1,
70                          'gsdevice' => $conf{'GSDEVICE'},
71                          'gsname' => $conf{'GSNAME'},
72                          'res' => $conf{'RESOLUTION'},
73                          'paper' => $conf{'PAPERSIZE'},
74                          'eof' => lc($conf{'SENDEOF'}),
75                          'double' => lc($conf{'DOUBLEPAGE'}),
76                          'gsopts' => $conf{'GSOPTS'},
77                          'ddesc' => $prn->{'description'},
78                          'desc' => $conf{'GSNAME'} ? $conf{'GSNAME'}
79                                                    : $prn->{'description'} };
80                 }
81         }
82 elsif (join(@lines) eq $base_driver_text) {
83         # Looks like a 2.4 caldera driver!
84         &read_env_file("$driver_dir/$_[1]->{'name'}", \%conf);
85         if ($conf{'GSDEVICE'} eq 'NET' || $conf{'GSDEVICE'} eq 'RAW') {
86                 # Driver isn't even used
87                 return { 'mode' => 0,
88                          'desc' => 'None' };
89                 }
90         else {
91                 # A new caldera printer driver
92                 open(COAS, $config{'coas_printers'});
93                 local $plist = &parse_coas(COAS);
94                 close(COAS);
95                 local ($prn, $p, $type);
96                 foreach $p (values %$plist) {
97                         $type = ref($p->{'type'}) ? $p->{'type'}->{'0'}
98                                                   : $p->{'type'};
99                         $prn = $p if ($type eq $conf{'GSDEVICE'} && !$prn &&
100                                 ($p->{'description'} eq $conf{'DESC'} ||
101                                  $p->{'description'} eq $conf{'GSNAME'}));
102                         }
103                 if (!$prn) {
104                         foreach $p (values %$plist) {
105                                 $type = ref($p->{'type'}) ? $p->{'type'}->{'0'}
106                                                           : $p->{'type'};
107                                 $prn = $p if ($type eq $conf{'GSDEVICE'} &&
108                                               !$prn);
109                                 }
110                         }
111                 return { 'mode' => 1,
112                          'gsdevice' => $conf{'GSDEVICE'},
113                          'gsname' => $conf{'GSNAME'},
114                          'res' => $conf{'RESOLUTION'},
115                          'paper' => $conf{'PAPERSIZE'},
116                          'eof' => lc($conf{'SENDEOF'}),
117                          'double' => lc($conf{'DOUBLEPAGE'}),
118                          'gsopts' => $conf{'GSOPTS'},
119                          'upp' => $conf{'UPP'},
120                          'ddesc' => $prn->{'description'},
121                          'desc' => $conf{'GSNAME'} ? $conf{'GSNAME'}
122                                                    : $prn->{'description'} };
123                 }
124         }
125 else {
126         # A driver of some kind, but not caldera's
127         return { 'mode' => 2,
128                  'file' => $_[0],
129                  'desc' => $_[0] };
130         }
131 }
132
133 # create_windows_driver(&printer, &driver)
134 sub create_windows_driver
135 {
136 return &create_webmin_windows_driver(@_);
137 }
138
139 # create_driver(&printer, &driver)
140 sub create_driver
141 {
142 &lock_file("$driver_dir/$_[0]->{'name'}");
143 if ($_[1]->{'mode'} == 0) {
144         unlink("$driver_dir/$_[0]->{'name'}");
145         &unlock_file("$driver_dir/$_[0]->{'name'}");
146         return undef;
147         }
148 elsif ($_[1]->{'mode'} == 2) {
149         unlink("$driver_dir/$_[0]->{'name'}");
150         &unlock_file("$driver_dir/$_[0]->{'name'}");
151         return $_[1]->{'file'};
152         }
153 else {
154         # Create or update the parameters file
155         local %conf;
156         &read_env_file("$driver_dir/$_[0]->{'name'}", \%conf);
157         $conf{'GSDEVICE'} = $_[1]->{'gsdevice'};
158         $conf{'GSNAME'} = $_[1]->{'gsname'};
159         $conf{'NAME'} = $_[0]->{'name'};
160         $conf{'RESOLUTION'} = $_[1]->{'res'};
161         $conf{'PAPERSIZE'} = $_[1]->{'paper'};
162         $conf{'DESC'} = $_[0]->{'desc'};
163         $conf{'SENDEOF'} = $_[1]->{'eof'};
164         $conf{'DOUBLEPAGE'} = $_[1]->{'double'};
165         $conf{'GSOPTS'} = $_[1]->{'gsopts'};
166         $conf{'UPP'} = $_[1]->{'upp'};
167         &write_env_file("$driver_dir/$_[0]->{'name'}", \%conf);
168         &unlock_file("$driver_dir/$_[0]->{'name'}");
169
170         &lock_file("$config{'spool_dir'}/$_[0]->{'name'}");
171         mkdir("$config{'spool_dir'}/$_[0]->{'name'}", 0755);
172         &unlock_file("$config{'spool_dir'}/$_[0]->{'name'}");
173         local $drv = "$config{'spool_dir'}/$_[0]->{'name'}/printfilter";
174         &lock_file($drv);
175         if ($gconfig{'os_version'} >= 2.4) {
176                 # Create the 2.4 driver program
177                 &copy_source_dest($base_driver, $drv);
178                 }
179         else {
180                 # Create the 2.3 driver program
181                 open(DRIVER, $base_driver);
182                 local @lines = <DRIVER>;
183                 close(DRIVER);
184                 &open_tempfile(DRV, ">$drv");
185                 &print_tempfile(DRV, "#!/bin/bash\n");
186                 &print_tempfile(DRV, "source $driver_dir/$_[0]->{'name'}\n");
187                 &print_tempfile(DRV, @lines);
188                 &close_tempfile(DRV);
189                 }
190         &unlock_file($drv);
191         return $drv;
192         }
193 }
194
195 # delete_driver(name)
196 sub delete_driver
197 {
198 &delete_webmin_driver($_[0]);
199 &lock_file("$driver_dir/$_[0]");
200 unlink("$driver_dir/$_[0]");
201 &unlock_file("$driver_dir/$_[0]");
202 }
203
204 # driver_input(&printer, &driver)
205 sub driver_input
206 {
207 local $mode = $_[1]->{'mode'};
208 printf "<tr> <td><input type=radio name=mode value=0 %s> %s</td>\n",
209         $mode == 0 ? 'checked' : '', $text{'caldera_none'};
210 print "<td>($text{'caldera_nonemsg'})</td> </tr>\n";
211 printf "<tr> <td><input type=radio name=mode value=2 %s> %s</td>",
212         $mode == 2 ? 'checked' : '', $text{'caldera_prog'};
213 printf "<td><input name=program size=40 value='%s'></td> </tr>\n",
214         $mode == 2 ? $_[0]->{'iface'} : '';
215
216 # Normal driver options
217 printf "<tr> <td valign=top><input type=radio name=mode value=1 %s> %s</td>\n",
218         $mode == 1 ? 'checked' : '', $text{'caldera_coas'};
219 print "<td><table width=100%>\n";
220
221 local $sels = $gconfig{'os_version'} < 2.4 ? 5 : 10;
222 print "<tr> <td valign=top><b>$text{'caldera_printer'}</b></td>\n";
223 print "<td colspan=3><select size=$sels name=gsdevice onChange='setres(0)'>\n";
224 open(COAS, $config{'coas_printers'});
225 local $plist = &parse_coas(COAS);
226 close(COAS);
227 local ($i, $j, $p, $k, $found, $select_res);
228 foreach $p (values %$plist) {
229         if ($p->{'description'} eq $_[1]->{'gsname'} &&
230             $p->{'type'}->{'0'} ne $_[1]->{'gsdevice'}) {
231                 # COAS has changed the device
232                 $_[1]->{'gsname'} = undef;
233                 }
234         }
235 foreach $k (sort { $a <=> $b } keys %$plist) {
236         $p = $plist->{$k};
237         local $type = ref($p->{'type'}) ? $p->{'type'}->{'0'}
238                                         : $p->{'type'};
239         next if ($type =~ /NET|RAW/);
240         local @thisres = values %{$p->{'resolution'}};
241         #local $got = ($_[1]->{'gsname'} eq $p->{'description'} &&
242         #             $_[1]->{'gsdevice'} eq $type) ||
243         #            (!$_[1]->{'gsname'} && !$found &&
244         #             $_[1]->{'gsdevice'} eq $type);
245         local $got = $_[1]->{'ddesc'} eq $p->{'description'};
246         printf "<option %s value='%s'>%s\n",
247                 $got ? 'selected' : '',
248                 $p->{'description'}.";".join(";", @thisres),
249                 $p->{'description'};
250         $found = $p if ($got);
251         $select_res = &indexof($_[1]->{'res'}, @thisres) if ($got);
252         map { $gotres{$_}++ } @thisres;
253         }
254 print "</select><select name=res size=$sels>\n";
255 foreach $r (sort { $a <=> $b} keys %gotres) {
256         printf "<option %s>%s\n",
257                 $_[1]->{'res'} eq $r ? 'selected' : '', $r;
258         }
259 print "</select></td> </tr>\n";
260
261 print "<tr> <td><b>$text{'caldera_eof'}</b></td>\n";
262 printf "<td><input type=radio name=eof value=true %s> $text{'yes'}\n",
263         $_[1]->{'eof'} eq 'true' ? 'checked' : '';
264 printf "<input type=radio name=eof value=false %s> $text{'no'}</td>\n",
265         $_[1]->{'eof'} eq 'true' ? '' : 'checked';
266
267 print "<td><b>$text{'caldera_paper'}</b></td> <td><select name=paper>\n";
268 foreach $p (sort { $a cmp $b } keys %paper_sizes) {
269         printf "<option value='%s' %s>%s\n",
270                 $p, $_[1]->{'paper'} eq $p ? 'selected' : '',
271                 $paper_sizes{$p};
272         }
273 print "</select></td> </tr>\n";
274
275 print "<tr> <td><b>$text{'caldera_double'}</b></td>\n";
276 printf "<td><input type=radio name=double value=true %s> $text{'yes'}\n",
277         $_[1]->{'double'} eq 'true' ? 'checked' : '';
278 printf "<input type=radio name=double value=false %s> $text{'no'}</td>\n",
279         $_[1]->{'double'} eq 'true' ? '' : 'checked';
280
281 if ($found) {
282         $_[1]->{'gsopts'} =~ s/\s*$found->{'gsoptions'}\s*//;
283         }
284 print "<td><b>$text{'caldera_gsopts'}</b></td>\n";
285 printf "<td><input name=gsopts size=30 value='%s'></td> </tr>\n",
286         $_[1]->{'gsopts'};
287
288 print "</table></td></tr>\n";
289
290 if ($gconfig{'os_version'} < 2.4) {
291         # Uniprint driver options
292         printf "<tr> <td valign=top><input type=radio name=mode value=3 %s> %s</td>\n",
293                 $mode == 3 ? 'checked' : '', $text{'caldera_uniprint'};
294         print "<td><table width=100%>\n";
295
296         print "<tr> <td valign=top><b>$text{'caldera_printer'}</b></td>\n";
297         print "<td colspan=3><select name=uniprint size=5>\n";
298         foreach $u (&list_uniprint()) {
299                 printf "<option value=%s %s>%s\n",
300                         $u->[0], $u->[0] eq $_[1]->{'upp'} ? 'selected' : '',
301                         $u->[1];
302                 }
303         closedir(DIR);
304         print "</select></td> </tr>\n";
305
306         print "<tr> <td><b>$text{'caldera_eof'}</b></td>\n";
307         printf "<td><input type=radio name=ueof value=true %s> $text{'yes'}\n",
308                 $_[1]->{'eof'} eq 'true' ? 'checked' : '';
309         printf "<input type=radio name=ueof value=false %s> $text{'no'}</td>\n",
310                 $_[1]->{'eof'} eq 'true' ? '' : 'checked';
311
312         print "<td><b>$text{'caldera_paper'}</b></td> <td><select name=upaper>\n";
313         foreach $p (sort { $a cmp $b } keys %paper_sizes) {
314                 printf "<option value='%s' %s>%s\n",
315                         $p, $_[1]->{'paper'} eq $p ? 'selected' : '',
316                         $paper_sizes{$p};
317                 }
318         print "</select></td> </tr>\n";
319
320         print "<tr> <td><b>$text{'caldera_double'}</b></td>\n";
321         printf "<td><input type=radio name=udouble value=true %s> $text{'yes'}\n",
322                 $_[1]->{'double'} eq 'true' ? 'checked' : '';
323         printf "<input type=radio name=udouble value=false %s> $text{'no'}</td>\n",
324                 $_[1]->{'double'} eq 'true' ? '' : 'checked';
325
326         print "</table></td></tr>\n";
327         }
328
329 return <<EOF;
330 <script>
331 function setres(sel)
332 {
333 var idx = document.forms[0].gsdevice.selectedIndex;
334 var v = new String(document.forms[0].gsdevice.options[idx].value);
335 var vv = v.split(";");
336 var res = document.forms[0].res;
337 res.length = 0;
338 for(var i=1; i<vv.length; i++) {
339         res.options[i-1] = new Option(vv[i], vv[i]);
340         }
341 if (res.length > 0) {
342         res.options[sel].selected = true;
343         }
344 }
345 setres($select_res);
346 </script>
347 EOF
348 }
349
350 # parse_driver()
351 # Parse driver selection from %in and return a driver structure
352 sub parse_driver
353 {
354 if ($in{'mode'} == 0) {
355         return { 'mode' => 0 };
356         }
357 elsif ($in{'mode'} == 2) {
358         $in{'program'} =~ /^(\S+)/ && -x $1 ||
359                 &error(&text('caldera_eprog', $in{'program'}));
360         return { 'mode' => 2,
361                  'file' => $in{'program'} };
362         }
363 elsif ($in{'mode'} == 1) {
364         # Normal ghostscript driver
365         open(COAS, $config{'coas_printers'});
366         local $plist = &parse_coas(COAS);
367         close(COAS);
368         $in{'gsdevice'} || &error($text{'caldera_edriver'});
369         $in{'gsdevice'} =~ s/;(.*)$//;
370         local ($p, $prn);
371         foreach $p (values %$plist) {
372                 $prn = $p if ($p->{'description'} eq $in{'gsdevice'});
373                 }
374         local $gsdevice = ref($prn->{'type'}) ? $prn->{'type'}->{'0'}
375                                               : $prn->{'type'},
376         $gsdevice eq 'PostScript' || $in{'res'} ||
377                 &error($text{'caldera_eres'});
378         if ($prn->{'gsoptions'}) {
379                 $in{'gsopts'} .= " ".$prn->{'gsoptions'};
380                 }
381         return { 'mode' => 1,
382                  'gsdevice' => $gsdevice,
383                  'upp' => $prn->{'uniprint'},
384                  'gsname' => $in{'gsdevice'},
385                  'res' => $in{'res'},
386                  'paper' => $in{'paper'},
387                  'eof' => $in{'eof'},
388                  'double' => $in{'double'},
389                  'gsopts' => $in{'gsopts'} };
390         }
391 else {
392         # Uniprint ghostscript driver under 2.3
393         $in{'uniprint'} || &error($text{'caldera_edriver'});
394         return { 'mode' => 3,
395                  'gsdevice' => 'uniprint',
396                  'upp' => $in{'uniprint'},
397                  'paper' => $in{'upaper'},
398                  'eof' => $in{'ueof'},
399                  'double' => $in{'udouble'} };
400         }
401 }
402
403 # parse_coas(handle)
404 sub parse_coas
405 {
406 local $h = $_[0];
407 local (%rv, $_);
408 while(<$h>) {
409         s/#.*$//g;
410         s/\r|\n//g;
411         if (/^\s*(\S+)\s+{/) {
412                 # start of a section
413                 local $k = $1;
414                 $rv{$k} = &parse_coas($h);
415                 }
416         elsif (/^\s*}/) {
417                 # end of a section
418                 last;
419                 }
420         elsif (/^\s*(\S+)\s+(.*)/) {
421                 # a value in a section
422                 $rv{$1} = $2;
423                 }
424         }
425 return \%rv;
426 }
427
428 1;
429