Handle hostnames with upper-case letters
[webmin.git] / lpadmin / redhat-driver.pl
1 # redhat-driver.pl
2 # Functions for printer drivers as created by redhat
3
4 %paper_sizes = ( 'a4', 'A4',
5                  'a3', 'A3',
6                  'letter', 'US Letter',
7                  'legal', 'Legal',
8                  'ledger', 'Ledger' );
9 $rhs_drivers_file = "/usr/lib/rhs/rhs-printfilters/printerdb";
10 $base_driver = "/usr/lib/rhs/rhs-printfilters/master-filter";
11 $smb_driver = "/usr/lib/rhs/rhs-printfilters//smbprint";
12 $ncp_driver = "/usr/lib/rhs/rhs-printfilters//ncpprint";
13
14 # is_windows_driver(path, %driver)
15 # Returns a driver structure if some path is a windows driver
16 sub is_windows_driver
17 {
18 local $sd = "$config{'spool_dir'}/$_[1]->{'name'}";
19 if (($_[0] eq $smb_driver || $_[0] eq "$sd/filter") && -r "$sd/.config" &&
20     $_[1]->{'comment'} =~ /^##PRINTTOOL3##\s+SMB/) {
21         # Looks like a redhat SMB driver
22         local %sconfig;
23         &read_env_file("$sd/.config", \%sconfig);
24         $sconfig{'share'} =~ /^\\\\(.*)\\(.*)$/;
25         return { 'server' => $1,
26                  'share' => $2,
27                  'user' => $sconfig{'user'},
28                  'pass' => $sconfig{'password'},
29                  'workgroup' => $sconfig{'workgroup'},
30                  'program' => $_[0] eq "$sd/filter" ? "$sd/filter" : undef };
31         }
32 return undef;
33 }
34
35 # is_driver(path, &printer)
36 # Returns a structure containing the details of a driver
37 sub is_driver
38 {
39 if (!$_[0]) {
40         return { 'mode' => 0,
41                  'desc' => "$text{'redhat_none'}" };
42         }
43 local $sd = "$config{'spool_dir'}/$_[1]->{'name'}";
44 if ($_[0] eq "$sd/filter" &&
45     $_[1]->{'comment'} =~ /^##PRINTTOOL3##\s+(LOCAL|REMOTE|SMB)\s+(\S+)\s+(\S+)\s+(\S+)\s+\S+\s+(\S+)\s+(\S+)\s+/) {
46         # Looks like a redhat driver ..
47         local ($r, $rhs);
48         foreach $r (&read_rhs_drivers()) {
49                 $rhs = $r if ($r->{'name'} eq $5);
50                 }
51         local (%general, %postscript, %textonly);
52         &read_env_file("$sd/general.cfg", \%general);
53         &read_env_file("$sd/postscript.cfg", \%postscript);
54         &read_env_file("$sd/textonly.cfg", \%textonly);
55         return { 'mode' => 1,
56                  'gsdevice' => $postscript{'GSDEVICE'},
57                  'res' => $postscript{'RESOLUTION'},
58                  'paper' => $postscript{'PAPERSIZE'},
59                  'gsopts' => $postscript{'EXTRA_GS_OPTIONS'},
60                  'eof' => lc($textonly{'TEXT_SEND_EOF'}),
61                  'nup' => $postscript{'NUP'},
62                  'hmargin' => $postscript{'RTLFTMAR'},
63                  'vmargin' => $postscript{'TOPBOTMAR'},
64                  'crlf' => $textonly{'CRLFTRANS'},
65                  'bpp' => $postscript{'COLOR'} =~ /-dBitsPerPixel=(\d+)/ ? $1
66                                 : $postscript{'COLOR'},
67                  'rhsname' => $rhs->{'name'},
68                  'desc' => $rhs->{'desc'} };
69         }
70 else {
71         # Some other kind of driver
72         return { 'mode' => 2,
73                  'file' => $_[0],
74                  'desc' => $_[0] };
75         }
76 }
77
78 # create_windows_driver(&printer, &driver)
79 # Creates a new windows printer driver
80 sub create_windows_driver
81 {
82 local $sd = "$config{'spool_dir'}/$_[0]->{'name'}";
83
84 # Create the config file and driver
85 local %sconfig;
86 &read_env_file("$sd/.config", \%sconfig);
87 $sconfig{'share'} = "\\\\$_[1]->{'server'}\\$_[1]->{'share'}";
88 $sconfig{'hostip'} = $_[1]->{'server'} eq $config{'hostip'} ?
89                         $sconfig{'hostip'} : undef;
90 $sconfig{'user'} = $_[1]->{'user'};
91 $sconfig{'password'} = $_[1]->{'pass'};
92 $sconfig{'workgroup'} = $_[1]->{'workgroup'};
93 &lock_file($sd);
94 mkdir($sd, 0755);
95 &unlock_file($sd);
96 &open_lock_tempfile(ENV, ">$sd/.config");
97 &print_tempfile(ENV, "share='$sconfig{'share'}'\n");
98 &print_tempfile(ENV, "hostip=$sconfig{'hostip'}\n");
99 &print_tempfile(ENV, "user='$sconfig{'user'}'\n");
100 &print_tempfile(ENV, "password='$sconfig{'password'}'\n");
101 &print_tempfile(ENV, "workgroup='$sconfig{'workgroup'}'\n");
102 &close_tempfile(ENV);
103
104 # Setup the comment and return the driver
105 local $drv = &is_driver($_[1]->{'program'}, $_[0]);
106 if ($drv->{'mode'} == 1) {
107         local %general;
108         &lock_file("$sd/general.cfg");
109         &read_env_file("$sd/general.cfg", \%general);
110         $general{'PRINTER_TYPE'} = 'SMB';
111         &write_env_file("$sd/general.cfg", \%general, 1);
112         &unlock_file("$sd/general.cfg");
113         $_[0]->{'comment'} =~ s/\s+LOCAL\s+/ SMB /;
114         return $_[1]->{'program'};
115         }
116 else {
117         $_[0]->{'comment'} = "##PRINTTOOL3## SMB";
118         return $smb_driver;
119         }
120 }
121
122 # create_driver(&printer, &driver)
123 # Creates a new local printer driver and returns the path
124 sub create_driver
125 {
126 local ($prn, $drv) = @_;
127 if ($drv->{'mode'} == 0) {
128         $prn->{'comment'} =
129                 join(" ", "##PRINTTOOL3##",
130                           $prn->{'rhost'} ? "REMOTE" : "LOCAL");
131         return undef;
132         }
133 elsif ($drv->{'mode'} == 2) {
134         $prn->{'comment'} =
135                 join(" ", "##PRINTTOOL3##",
136                           $prn->{'rhost'} ? "REMOTE" : "LOCAL");
137         return $drv->{'file'};
138         }
139 else {
140         if (!-d $config{'spool_dir'}) {
141                 &lock_file($config{'spool_dir'});
142                 mkdir($config{'spool_dir'}, 0755);
143                 &unlock_file($config{'spool_dir'});
144                 &system_logged("chown $config{'iface_owner'} $config{'spool_dir'}");
145                 }
146         local $sd = "$config{'spool_dir'}/$_[0]->{'name'}";
147
148         # create the config files
149         local (%general, %postscript, %textonly);
150         &lock_file("$sd/general.cfg");
151         &lock_file("$sd/postscript.cfg");
152         &lock_file("$sd/textonly.cfg");
153         &read_env_file("$sd/general.cfg", \%general);
154         &read_env_file("$sd/postscript.cfg", \%postscript);
155         &read_env_file("$sd/textonly.cfg", \%textonly);
156         if (!%general) {
157                 # setup for the first time..
158                 %general = ( 'DESIRED_TO', 'ps',
159                              'ASCII_TO_PS', 'NO' );
160                 }
161         $general{'PAPERSIZE'} = $drv->{'paper'};
162         $general{'PRINTER_TYPE'} = $_[0]->{'rhost'} ? "REMOTE" : "LOCAL";
163         $postscript{'GSDEVICE'} = $drv->{'gsdevice'};
164         $postscript{'RESOLUTION'} = $drv->{'res'} ? $drv->{'res'} : "NAxNA";
165         $postscript{'COLOR'} = $drv->{'bpp'} =~ /^\d+$/ ?
166                         "-dBitsPerPixel=$drv->{'bpp'}" : $drv->{'bpp'};
167         $postscript{'PAPERSIZE'} = $drv->{'paper'};
168         $postscript{'EXTRA_GS_OPTIONS'} = $drv->{'gsopts'};
169         $postscript{'PS_SEND_EOF'} = uc($drv->{'eof'});
170         $postscript{'NUP'} = $drv->{'nup'};
171         $postscript{'RTLFTMAR'} = $drv->{'hmargin'};
172         $postscript{'TOPBOTMAR'} = $drv->{'vmargin'};
173         $textonly{'TEXT_SEND_EOF'} = uc($drv->{'eof'});
174         $textonly{'CRLFTRANS'} = $drv->{'crlf'};
175         &lock_file($sd);
176         mkdir($sd, 0755);
177         &unlock_file($sd);
178         &write_env_file("$sd/general.cfg", \%general, 1);
179         &write_env_file("$sd/postscript.cfg", \%postscript);
180         &write_env_file("$sd/textonly.cfg", \%textonly);
181         &unlock_file("$sd/general.cfg");
182         &unlock_file("$sd/postscript.cfg");
183         &unlock_file("$sd/textonly.cfg");
184
185         # create the comment
186         $_[0]->{'comment'} =
187                 join(" ", "##PRINTTOOL3##",
188                           $_[0]->{'rhost'} ? "REMOTE" : "LOCAL",
189                           $drv->{'gsdevice'},
190                           $drv->{'res'} ? $drv->{'res'} : "NAxNA",
191                           $drv->{'paper'},
192                           "{}",
193                           $drv->{'rhsname'},
194                           $drv->{'bpp'} ? $drv->{'bpp'} : "Default",
195                           $drv->{'crlf'} ? 1 : "{}" );
196
197         # copy the standard filter into place
198         &lock_file("$sd/filter");
199         unlink("$sd/filter");
200         &copy_source_dest("$base_driver", "$sd/filter");
201         &unlock_file("$sd/filter");
202         return "$sd/filter";
203         }
204 }
205
206 # delete_driver(name)
207 sub delete_driver
208 {
209 local $sd = "$config{'spool_dir'}/$_[0]";
210 unlink("$sd/.config", "$sd/filter");
211 unlink("$sd/general.cfg", "$sd/postscript.cfg", "$sd/textonly.cfg");
212 }
213
214 # driver_input(&printer, &driver)
215 sub driver_input
216 {
217 local ($prn, $drv) = @_;
218
219 printf "<tr> <td><input type=radio name=mode value=0 %s> %s</td>\n",
220         $drv->{'mode'} == 0 ? "checked" : "", $text{'redhat_none'};
221 print "<td>($text{'redhat_nonemsg'})</td> </tr>\n";
222
223 printf "<tr> <td><input type=radio name=mode value=2 %s> %s</td>\n",
224         $drv->{'mode'} == 2 ? "checked" : "", $text{'redhat_prog'};
225 printf "<td><input name=iface value=\"%s\" size=35></td> </tr>\n",
226         $drv->{'mode'} == 2 ? $drv->{'file'} : "";
227
228 printf "<tr> <td valign=top><input type=radio name=mode value=1 %s>\n",
229         $drv->{'mode'} == 1 ? "checked" : "";
230 print "$text{'redhat_driver'}</td> <td><table width=100%>";
231
232 print "<tr> <td valign=top><b>$text{'redhat_printer'}</b></td>\n";
233 print "<td colspan=3><select size=5 name=gsdevice onChange='setres(0)'>\n";
234 local @rhs = &read_rhs_drivers();
235 local ($r, $select_res, $rr);
236 local $bpp = $drv->{'bpp'};
237 local $res = $drv->{'res'};
238 foreach $r (@rhs) {
239         local @res;
240         if ($r->{'res'} && $r->{'bpp'}) {
241                 foreach $rr (@{$r->{'res'}}) {
242                         push(@res, map { "$rr->[0]x$rr->[1], $_->[0] DPI, $_->[1]" } @{$r->{'bpp'}});
243                         }
244                 for($i=0; $i<@res; $i++) {
245                         $select_res = $i if ($res[$i] =~ /^$res, $bpp / &&
246                                              $drv->{'rhsname'} eq $r->{'name'});
247                         }
248                 }
249         elsif ($r->{'res'}) {
250                 @res = map { "$_->[0]x$_->[1]" } @{$r->{'res'}};
251                 $select_res = &indexof($res, @res)
252                         if ($drv->{'rhsname'} eq $r->{'name'});
253                 }
254         else {
255                 @res = map { "$_->[1], $_->[0]" } @{$r->{'bpp'}};
256                 for($i=0; $i<@res; $i++) {
257                         $select_res = $i if ($res[$i] =~ / $bpp$/ &&
258                                              $drv->{'rhsname'} eq $r->{'name'});
259                         }
260                 }
261         printf "<option value='%s' %s>%s\n",
262                 $r->{'name'}.";".join(";", @res),
263                 $drv->{'rhsname'} eq $r->{'name'} ? 'selected' : '',
264                 $r->{'desc'};
265         }
266 print "</select><select size=5 name=res width=250>\n";
267 print "</select></td> </tr>\n";
268
269 print "<tr> <td><b>$text{'redhat_eof'}</b></td>\n";
270 printf "<td><input type=radio name=eof value=yes %s> $text{'yes'}\n",
271         $drv->{'eof'} eq 'yes' ? 'checked' : '';
272 printf "<input type=radio name=eof value=no %s> $text{'no'}</td>\n",
273         $drv->{'eof'} eq 'yes' ? '' : 'checked';
274
275 print "<td><b>$text{'redhat_paper'}</b></td> <td><select name=paper>\n";
276 foreach $p (sort { $a cmp $b } keys %paper_sizes) {
277         printf "<option value='%s' %s>%s\n",
278                 $p, $drv->{'paper'} eq $p ? 'selected' : '',
279                 $paper_sizes{$p};
280         }
281 print "</select></td> </tr>\n";
282
283 print "<tr> <td><b>$text{'redhat_pages'}</b></td>\n";
284 print "<td><select name=nup>\n";
285 foreach $p (1, 2, 4, 8) {
286         printf "<option %s>%s\n",
287                 $drv->{'nup'} == $p ? 'selected' : '', $p;
288         }
289 print "</select></td>\n";
290
291 print "<td><b>$text{'redhat_gsopts'}</b></td>\n";
292 printf "<td><input name=gsopts size=30 value='%s'></td> </tr>\n",
293         $drv->{'gsopts'};
294
295 print "<tr> <td><b>$text{'redhat_hmargin'}</b></td>\n";
296 printf "<td><input name=hmargin size=6 value='%s'></td>\n",
297         $drv->{'hmargin'} ? $drv->{'hmargin'} : 18;
298
299 print "<td><b>$text{'redhat_vmargin'}</b></td>\n";
300 printf "<td><input name=vmargin size=6 value='%s'></td> </tr>\n",
301         $drv->{'vmargin'} ? $drv->{'vmargin'} : 18;
302
303 print "<tr> <td><b>$text{'redhat_crlf'}</b></td>\n";
304 printf "<td><input type=radio name=crlf value=1 %s> $text{'yes'}\n",
305         $drv->{'crlf'} ? 'checked' : '';
306 printf "<input type=radio name=crlf value=0 %s> $text{'no'}</td>\n",
307         $drv->{'crlf'} ? '' : 'checked';
308
309 print "</table></td></tr>\n";
310
311 return <<EOF;
312 <script>
313 function setres(sel)
314 {
315 var idx = document.forms[0].gsdevice.selectedIndex;
316 var v = new String(document.forms[0].gsdevice.options[idx].value);
317 var vv = v.split(";");
318 var res = document.forms[0].res;
319 res.length = 0;
320 for(var i=1; i<vv.length; i++) {
321         res.options[i-1] = new Option(vv[i], i-1);
322         }
323 if (res.length > 0) {
324         res.options[sel].selected = true;
325         }
326 }
327 setres($select_res);
328 </script>
329 EOF
330
331 }
332
333 # parse_driver()
334 # Parse driver selection from %in and return a driver structure
335 sub parse_driver
336 {
337 if ($in{'mode'} == 0) {
338         return { 'mode' => 0 };
339         }
340 elsif ($in{'mode'} == 2) {
341         (-x $in{'iface'}) || &error(&text('redhat_eprog', $in{'iface'}));
342         return { 'mode' => 2,
343                  'file' => $in{'iface'} };
344         }
345 elsif ($in{'mode'} == 1) {
346         $in{'gsdevice'} || &error($text{'redhat_edriver'});
347         $in{'hmargin'} =~ /^\d+$/ ||
348                 &error($text{'redhat_ehmargin'});
349         $in{'vmargin'} =~ /^\d+$/ ||
350                 &error($text{'redhat_evmargin'});
351         local $drv = { 'mode' => 1,
352                        'eof' => $in{'eof'},
353                        'paper' => $in{'paper'},
354                        'nup' => $in{'nup'},
355                        'gsopts' => $in{'gsopts'},
356                        'hmargin' => $in{'hmargin'},
357                        'vmargin' => $in{'vmargin'},
358                        'crlf' => $in{'crlf'} };
359
360         local ($r, $rhs);
361         $in{'gsdevice'} =~ s/;.*$//;
362         foreach $r (&read_rhs_drivers()) {
363                 $rhs = $r if ($r->{'name'} eq $in{'gsdevice'});
364                 }
365         if ($rhs->{'res'} && $rhs->{'bpp'}) {
366                 defined($in{'res'}) || &error($text{'redhat_eres'});
367                 local $bc = @{$rhs->{'bpp'}};
368                 local $rs = $rhs->{'res'}->[$in{'res'} / $bc];
369                 local $bp = $rhs->{'bpp'}->[$in{'res'} % $bc];
370                 $drv->{'res'} = $rs->[0].'x'.$rs->[1];
371                 $drv->{'bpp'} = $bp->[0];
372                 }
373         elsif ($rhs->{'res'}) {
374                 defined($in{'res'}) || &error($text{'redhat_eres'});
375                 local $rs = $rhs->{'res'}->[$in{'res'}];
376                 $drv->{'res'} = $rs->[0].'x'.$rs->[1];
377                 }
378         elsif ($rhs->{'bpp'}) {
379                 defined($in{'res'}) || &error($text{'redhat_eres'});
380                 $drv->{'bpp'} = $rhs->{'bpp'}->[$in{'res'}]->[0];
381                 }
382         $drv->{'rhsname'} = $rhs->{'name'};
383         $drv->{'gsdevice'} = $rhs->{'gsdriver'};
384         return $drv;
385         }
386 }
387
388 sub read_rhs_drivers
389 {
390 local (@rv, $drv);
391 open(DRV, $rhs_drivers_file);
392 while(<DRV>) {
393         s/#.*$//g;
394         s/\r|\n//g;
395         if (/^\s*StartEntry:\s+(.*)/) {
396                 push(@rv, $drv = { 'name' => $1 });
397                 }
398         elsif (/^\s*GSDriver:\s+(\S+)/) {
399                 $drv->{'gsdriver'} = $1;
400                 }
401         elsif (/^\s*Description:\s+{(.*)}/) {
402                 $drv->{'desc'} = $1;
403                 }
404         elsif (/^\s*Resolution:\s+{(\d+)}\s+{(\d+)}/) {
405                 push(@{$drv->{'res'}}, [ $1, $2 ]);
406                 }
407         elsif (/^\s*BitsPerPixel:\s+{(\S+)}\s+{(.*)}/) {
408                 push(@{$drv->{'bpp'}}, [ $1, $2 ]);
409                 }
410         }
411 close(DRV);
412 return @rv;
413 }
414
415 1;
416