Handle hostnames with upper-case letters
[webmin.git] / lpadmin / aix-lib.pl
1 # aix-lib.pl
2 # Functions for AIX-style printer management
3
4 # get_qconfig()
5 sub get_qconfig
6 {
7 local @rv;
8 local $prn;
9 local $lnum = 0;
10 open(CONF, $config{'printcap_file'});
11 while(<CONF>) {
12         s/\r|\n//g;
13         s/^\s*#.*$//;   
14         s/^\s*\*.*$//;  
15         if (/^(\S+):\s*$/) {
16                 # Start of a new printer
17                 $prn = { 'name' => $1,
18                           'line' => $lnum,
19                           'eline' => $lnum };
20                 push(@rv, $prn);
21                 }
22         elsif (/^\s+(\S+)\s*=\s*(.*)/ && $prn) {
23                 # Variable within a printer
24                 $prn->{'eline'} = $lnum;
25                 $prn->{'values'}->{lc($1)} = $2;
26                 }
27         $lnum++;
28         }
29 close(CONF);
30 return @rv;
31 }
32
33 # list_printers()
34 # Returns an array of known printer names
35 sub list_printers
36 {
37 local @qc = &get_qconfig();
38 local (@rv, $q);
39 foreach $q (@qc) {
40         if ($q->{'values'}->{'device'}) {
41                 # A real printer
42                 push(@rv, $q->{'name'});
43                 }
44         }
45 return &unique(@rv);
46 }
47
48 # get_printer(name, [nostatus])
49 # Returns a reference to an associative array of printer details
50 sub get_printer
51 {
52 if (!%enabled_cache) {
53         %enabled_cache = &get_enabled();
54         }
55
56 # Find the printer in qconfig
57 local @qc = &get_qconfig();
58 local %prn;
59 local ($real) = grep { $_->{'name'} eq $_[0] } @qc;
60 return undef if (!$real);
61 local ($device) = grep { $_->{'name'} eq $real->{'values'}->{'device'} &&
62                             $_->{'line'} > $real->{'line'} } @qc;
63
64 # Construct info object
65 $prn{'name'} = $_[0];
66 $prn{'accepting'} = uc($real->{'values'}->{'up'}) ne 'FALSE';
67 $prn{'enabled'} = $enabled_cache{$_[0]};
68 $prn{'desc'} = $real->{'values'}->{'device'};           # XXX
69 if ($real->{'values'}->{'rq'}) {
70         # Remote printer
71         $prn{'rhost'} = $real->{'values'}->{'host'};
72         $prn{'rqueue'} = $real->{'values'}->{'rq'};
73         if ($real->{'values'}->{'s_statfilter'} =~ /bsdshort/) {
74                 $prn{'type'} = 'bsd';
75                 }
76         elsif ($real->{'values'}->{'s_statfilter'} =~ /attshort/) {
77                 $prn{'type'} = 's5';
78                 }
79         elsif ($real->{'values'}->{'s_statfilter'} =~ /aixv2short/) {
80                 $prn{'type'} = 'aix2';
81                 }
82         else {
83                 # Assume AIX by default
84                 $prn{'type'} = 'aix';
85                 }
86         }
87 elsif ($device->{'values'}->{'backend'} =~ /piojetd\s+(\S+)\s+(\d+)/) {
88         # Jetdirect printer
89         $prn{'dhost'} = $1;
90         $prn{'dport'} = $2;
91         }
92 else {
93         # Local printer
94         $prn{'dev'} = "/dev/$_[0]";             # XXX
95         }
96 $prn{'banner'} = 1 if (lc($device->{'values'}->{'header'}) eq 'always');
97 if (!$prn{'dhost'} &&
98     $device->{'values'}->{'backend'} !~ /(rembak|piojetd|piob)/) {
99         $prn{'iface'} = $device->{'values'}->{'backend'};
100         }
101 return \%prn;
102
103 # XXX user access control
104 # XXX default printer?
105 # XXX remote system type
106 }
107
108 # get_jobs(printer)
109 sub get_jobs
110 {
111 local @jobs;
112 local $esc = quotemeta($_[0]);
113 local $doneheader;
114 open(LPQ, "lpq -P$esc |");
115 while(<LPQ>) {
116         s/\r|\n//g;
117         if (/^\-\-\-/) {
118                 $doneheader++;
119                 }
120         elsif ($doneheader &&
121                /^\s+(\S+)\s+(\d+)\s+(\S+)\s+(\S+)/) {
122                 local $job = { 'id' => $2,
123                                'user' => $4,
124                                'file' => $3,
125                                'printing' => lc($1) eq "active" };
126                 push(@jobs, $job);
127                 }
128         }
129 close(LPQ);
130 return @jobs;
131 }
132
133 # printer_support(option)
134 sub printer_support
135 {
136 return $_[0] !~ /^(why|allow|default|msize|ctype|alias|sysv|ipp|rnoqueue)$/;
137 }
138
139 # create_printer(&details)
140 # Create a new printer
141 sub create_printer
142 {
143 local $lref = &read_file_lines($config{'printcap_file'});
144 push(@$lref, &qconfig_real_lines($_[0]));
145 push(@$lref, &qconfig_device_lines($_[0]));
146 &flush_file_lines();
147 &enable_disable($_[0]);
148 }
149
150 # modify_printer(&details)
151 # Change an existing printer
152 sub modify_printer
153 {
154 # Find old entry
155 local @qc = &get_qconfig();
156 local ($real) = grep { $_->{'name'} eq $_[0]->{'name'} } @qc;
157 $real || &error("Failed to find old printer!");
158 local ($device) = grep { $_->{'name'} eq $real->{'values'}->{'device'} &&
159                             $_->{'line'} > $real->{'line'} } @qc;
160
161 # Update lines in file
162 local $lref = &read_file_lines($config{'printcap_file'});
163 if ($device) {
164         splice(@$lref, $device->{'line'},
165                $device->{'eline'} - $device->{'line'} + 1,
166                &qconfig_device_lines($_[0], $device));
167         }
168 else {
169         splice(@$lref, $real->{'eline'} + 1, 0,
170                &qconfig_device_lines($_[0]));
171         }
172 splice(@$lref, $real->{'line'}, $real->{'eline'} - $real->{'line'} + 1,
173        &qconfig_real_lines($_[0], $real));
174 &flush_file_lines();
175 &enable_disable($_[0]);
176 }
177
178 # enable_disable(&printer)
179 # Enable or disable some printer
180 sub enable_disable
181 {
182 local %ena = &get_enabled();
183 if ($_[0]->{'enabled'} && !$ena{$_[0]->{'name'}}) {
184         &system_logged("enable ".quotemeta($_[0]->{'name'}));
185         }
186 elsif (!$_[0]->{'enabled'} && $ena{$_[0]->{'name'}}) {
187         &system_logged("disable ".quotemeta($_[0]->{'name'}));
188         }
189 }
190
191 # get_enabled()
192 # Returns a hash from printer names to their enabled statuses
193 sub get_enabled
194 {
195 local %ena;
196 open(ENA, "lpstat -s -W |");
197 while(<ENA>) {
198         s/\r|\n//g;
199         next if (/^Queue|\-\-\-\-/);
200         if (/^\s*(\S+)\s+(\S+)\s+(\S+)/) {
201                 $ena{$1} = $3 eq 'READY';
202                 }
203         }
204 close(ENA);
205 return %ena;
206 }
207
208 # delete_printer(name)
209 # Deletes some existing printer
210 sub delete_printer
211 {
212 # Find old entry
213 local @qc = &get_qconfig();
214 local ($real) = grep { $_->{'name'} eq $_[0] } @qc;
215 local ($device) = grep { $_->{'name'} eq $real->{'values'}->{'device'} &&
216                             $_->{'line'} > $real->{'line'} } @qc;
217
218 # Take lines out of file
219 local $lref = &read_file_lines($config{'printcap_file'});
220 if ($device) {
221         splice(@$lref, $device->{'line'},
222                $device->{'eline'} - $device->{'line'} + 1);
223         }
224 splice(@$lref, $real->{'line'},
225        $real->{'eline'} - $real->{'line'} + 1);
226 &flush_file_lines();
227 }
228
229 # qconfig_real_lines(&printer, [&old-real])
230 sub qconfig_real_lines
231 {
232 local $real = $_[1] || { 'name' => $_[0]->{'name'},
233                          'values' => { } };
234 $_[0]->{'desc'} ||= "$_[0]->{'name'}_device";
235 $real->{'values'}->{'device'} = $_[0]->{'desc'};
236 if ($_[0]->{'accepting'}) {
237         delete($real->{'values'}->{'up'});
238         }
239 else {
240         $real->{'values'}->{'up'} = 'FALSE';
241         }
242 if ($_[0]->{'rhost'}) {
243         $real->{'values'}->{'host'} = $_[0]->{'rhost'};
244         $real->{'values'}->{'rq'} = $_[0]->{'rqueue'};
245         if ($_[0]->{'type'} eq 'bsd') {
246                 $real->{'values'}->{'s_statfilter'} = "/usr/lpd/bsdshort";
247                 $real->{'values'}->{'l_statfilter'} = "/usr/lpd/bsdlong";
248                 }
249         elsif ($_[0]->{'type'} eq 's5') {
250                 $real->{'values'}->{'s_statfilter'} = "/usr/lpd/attshort";
251                 $real->{'values'}->{'l_statfilter'} = "/usr/lpd/attlong";
252                 }
253         elsif ($_[0]->{'type'} eq 'aix2') {
254                 $real->{'values'}->{'s_statfilter'} = "/usr/lpd/aixv2short";
255                 $real->{'values'}->{'l_statfilter'} = "/usr/lpd/aixv2long";
256                 }
257         else {
258                 $real->{'values'}->{'s_statfilter'} = "/usr/lpd/aixshort";
259                 $real->{'values'}->{'l_statfilter'} = "/usr/lpd/aixlong";
260                 }
261         }
262 else {
263         delete($real->{'values'}->{'host'});
264         delete($real->{'values'}->{'rq'});
265         delete($real->{'values'}->{'s_statfilter'});
266         delete($real->{'values'}->{'l_statfilter'});
267         }
268 return &qconfig_lines($real);
269 }
270
271 # qconfig_device_lines(&printer, [&old-device])
272 sub qconfig_device_lines
273 {
274 local $device = $_[1] || { 'name' => $_[0]->{'desc'},
275                            'values' => { } };
276 if ($_[0]->{'rhost'}) {
277         $device->{'values'}->{'backend'} = "/usr/lib/lpd/rembak";
278         }
279 elsif ($_[0]->{'dhost'}) {
280         $device->{'values'}->{'backend'} = "/usr/lib/lpd/pio/etc/piojetd $_[0]->{'dhost'} $_[0]->{'dport'}";
281         if (!$device->{'values'}->{'file'}) {
282                 local $dfile = "/var/spool/lpd/pio/\@local/dev/hp\@$_[0]->{'dhost'}#hpJetDirect#$_[0]->{'dport'}";
283                 $device->{'values'}->{'file'} = $dfile;
284                 &open_tempfile(DFILE, ">$dfile");
285                 &print_tempfile(DFILE, "desc\t=\thpJetDirect\n");
286                 &close_tempfile(DFILE);
287                 }
288         }
289 elsif ($_[0]->{'iface'}) {
290         $device->{'values'}->{'backend'} = $_[0]->{'iface'};
291         }
292 else {
293         $device->{'values'}->{'backend'} = "/usr/lib/lpd/piobe";
294         }
295 if ($_[0]->{'banner'}) {
296         $device->{'values'}->{'header'} = "always";
297         }
298 else {
299         $device->{'values'}->{'header'} = "never";
300         }
301 return &qconfig_lines($device);
302 }
303
304 sub qconfig_lines
305 {
306 local @rv = ( "$_[0]->{'name'}:" );
307 local $k;
308 foreach $k (keys %{$_[0]->{'values'}}) {
309         push(@rv, "\t$k = $_[0]->{'values'}->{$k}");
310         }
311 return @rv;
312 }
313
314 # cancel_job(printer, id)
315 # Cancels some print job
316 sub cancel_job
317 {
318 local $esc = quotemeta($_[0]);
319 local $iesc = quotemeta($_[1]);
320 local $out = &backquote_logged("lprm -P $esc $iesc 2>&1");
321 if ($?) { &error("cancel failed : <pre>$out</pre>"); }
322 sleep(1);
323 }
324
325 # sched_running()
326 # Returns the pid if lpsched is running, 0 if not, -1 if cannot be stopped
327 sub sched_running
328 {
329 local @qpid = &find_byname("qdaemon");
330 local @lpid = &find_byname("lpd");
331 if (@qpid && @lpid) { return $qpid[0]; }
332 return 0;
333 }
334
335 # start_sched()
336 # Start lpsched
337 sub start_sched
338 {
339 local $s;
340 foreach $s ("qdaemon", "lpd") {
341         if (!&find_byname($s)) {
342                 local $out = &backquote_logged("/usr/bin/startsrc -s$s 2>&1");
343                 if ($?) { &error("failed to start $s : <tt>$out</tt>"); }
344                 }
345         }
346 }
347
348 # stop_sched(pid)
349 # Stop the running lpsched process
350 sub stop_sched
351 {
352 local $s;
353 foreach $s ("qdaemon", "lpd") {
354         if (&find_byname($s)) {
355                 local $out = &backquote_logged("/usr/bin/stopsrc -s$s 2>&1");
356                 if ($?) { &error("failed to start $s : <tt>$out</tt>"); }
357                 }
358         }
359 }
360
361 # print_command(printer, file)
362 # Returns the command to print some file on some printer
363 sub print_command
364 {
365 local $esc = quotemeta($_[0]);
366 local $fesc = quotemeta($_[1]);
367 return "lpr -P $esc $fesc";
368 }
369
370 # check_print_system()
371 sub check_print_system
372 {
373 &has_command("qdaemon") || return &text('aix_ecmd', "<tt>qdaemon</tt>");
374 return undef;
375 }
376
377 # validate_printer(&printer)
378 # Performs extra OS-specific printer validation, and returns an error message
379 # if there is a problem
380 sub validate_printer
381 {
382 return $text{'aix_edesc'} if ($_[0]->{'desc'} !~ /^[a-z0-9\-\.\_\@]*$/i);
383 return undef;
384 }
385
386 sub remote_printer_types
387 {
388 return ( [ 'aix', 'AIX' ], [ 'bsd', 'BSD' ],
389          [ 's5', 'ATT SysV' ], [ 'aix2', 'AIX v2' ] );
390 }
391
392 @device_files = ("/dev/lp0", "/dev/lp1", "/dev/null" );
393 @device_names = (&text('aix_port', "0"), &text('aix_port', "1"),
394                  $text{'solaris_null'});
395