Fix hpux printing
[webmin.git] / lpadmin / lpadmin-lib.pl
1 # lpadmin-lib.pl
2 # Functions for configuring and adding printers
3
4 BEGIN { push(@INC, ".."); };
5 use WebminCore;
6 &init_config();
7 do "$config{'print_style'}-lib.pl";
8 if ($config{'driver_style'}) {
9         do "$config{'driver_style'}-driver.pl";
10         }
11 else {
12         do "webmin-driver.pl";
13         }
14 %access = &get_module_acl();
15
16 $drivers_directory = "$module_config_directory/drivers";
17
18 # dev_name(file)
19 sub dev_name
20 {
21 local($i);
22 for($i=0; $i<@device_files; $i++) {
23         if ($device_files[$i] eq $_[0]) { return $device_names[$i]; }
24         }
25 return $_[0];
26 }
27
28 # has_ghostscript()
29 # Does this system have ghostscript installed?
30 sub has_ghostscript
31 {
32 return &has_command($config{'gs_path'});
33 }
34
35 # has_smbclient()
36 # Does this system have smbclient installed?
37 sub has_smbclient
38 {
39 return &has_command($config{'smbclient_path'});
40 }
41
42 # has_hpnp()
43 # Does this system have hpnp installed?
44 sub has_hpnp
45 {
46 return &has_command($config{'hpnp_path'});
47 }
48
49 # create_webmin_driver(&printer, &driver)
50 # lpadmin drivers are files in /etc/webmin/lpadmin/drivers. Each is a
51 # dynamically generated shell script which calls GS
52 sub create_webmin_driver
53 {
54 # check for non-driver
55 if ($_[1]->{'mode'} == 0) {
56         return undef;
57         }
58 elsif ($_[1]->{'mode'} == 2) {
59         return $_[1]->{'program'};
60         }
61
62 local($drv, $d, $gsdrv, $res, $perl);
63 &lock_file($drivers_directory);
64 mkdir($drivers_directory, 0755);
65 &unlock_file($drivers_directory);
66 $drv = "$drivers_directory/$_[0]->{'name'}";
67
68 # Find ghostscript driver
69 if ($_[1]->{'mode'} == 3) {
70         $gsdrv = 'uniprint';
71         }
72 else {
73         foreach $d (&list_webmin_drivers()) {
74                 if ($d->[1] eq $_[1]->{'type'}) {
75                         $gsdrv = $d->[0];
76                         }
77                 }
78         }
79
80 # Create script to call GS
81 &open_lock_tempfile(DRV, ">$drv");
82 &print_tempfile(DRV, "#!/bin/sh\n");
83 &print_tempfile(DRV, "# Name: $_[0]->{'name'}\n");
84 &print_tempfile(DRV, "# Type: ",$_[1]->{'upp'} ? 'uniprint'
85                                                : $_[1]->{'type'},"\n");
86 &print_tempfile(DRV, "# DPI: ",$_[1]->{'upp'} ? $_[1]->{'upp'}
87                                               : $_[1]->{'dpi'},"\n");
88 if ($gconfig{'ld_env'}) {
89         &print_tempfile(DRV, "$gconfig{'ld_env'}=$gconfig{'ld_path'}\n");
90         }
91 &print_tempfile(DRV, "PATH=$gconfig{'path'}\n");
92 if ($config{'gs_fontpath'}) {
93         &print_tempfile(DRV, "GS_FONTPATH=$config{'gs_fontpath'}\n");
94         }
95 if ($config{'gs_lib'}) {
96         &print_tempfile(DRV, "GS_LIB=$config{'gs_lib'}\n");
97         }
98 &print_tempfile(DRV, "export $gconfig{'ld_env'} PATH GS_FONTPATH GS_LIB\n");
99 $res = $_[1]->{'upp'} ? "\@$_[1]->{'upp'}.upp" :
100        $_[1]->{'dpi'} ? "-r$_[1]->{'dpi'}" : "";
101 $perl = &get_perl_path();
102 if ($config{'iface_arg'}) {
103         for($i=0; $i<$config{'iface_arg'}-1; $i++) {
104                 &print_tempfile(DRV, "shift\n");
105                 }
106         &print_tempfile(DRV, "cat \$* | $perl -e 'while(<STDIN>) { print if (!/^\\s*#####/); }' >/tmp/\$\$.gsin\n");
107         }
108 else {
109         &print_tempfile(DRV, "$perl -e 'while(<STDIN>) { print if (!/^\\s*#####/); }' >/tmp/\$\$.gsin\n");
110         }
111 &print_tempfile(DRV, "$config{'gs_path'} -sOutputFile=/tmp/\$\$.gs -dSAFER -sDEVICE=$gsdrv $res -dNOPAUSE /tmp/\$\$.gsin </dev/null >/dev/null 2>&1\n");
112 &print_tempfile(DRV, "rm /tmp/\$\$.gsin\n");
113 &print_tempfile(DRV, "cat /tmp/\$\$.gs\n");
114 &print_tempfile(DRV, "rm /tmp/\$\$.gs\n");
115 &close_tempfile(DRV);
116 if ($config{'iface_owner'}) {
117         &system_logged("chown '$config{'iface_owner'}' '$drv' >/dev/null 2>&1");
118         }
119 &system_logged("chmod '$config{'iface_perms'}' '$drv' >/dev/null 2>&1");
120 return $drv;
121 }
122
123 # create_webmin_windows_driver(&printer, &driver)
124 # Create an interface program that can print to a remote windows printer
125 # using some printer driver
126 sub create_webmin_windows_driver
127 {
128 local($drv, $prog);
129 &lock_file($drivers_directory);
130 mkdir($drivers_directory, 0755);
131 &unlock_file($drivers_directory);
132 $drv = "$drivers_directory/$_[0]->{'name'}.smb";
133
134 # Create script to call smbclient
135 &open_lock_tempfile(DRV, ">$drv");
136 &print_tempfile(DRV, "#!/bin/sh\n");
137 &print_tempfile(DRV, "# Name: $_[0]->{'name'}\n");
138 &print_tempfile(DRV, "# Server: $_[1]->{'server'}\n");
139 &print_tempfile(DRV, "# Share: $_[1]->{'share'}\n");
140 &print_tempfile(DRV, "# User: $_[1]->{'user'}\n");
141 &print_tempfile(DRV, "# Password: $_[1]->{'pass'}\n");
142 &print_tempfile(DRV, "# Workgroup: $_[1]->{'workgroup'}\n");
143 &print_tempfile(DRV, "# Program: $_[1]->{'program'}\n");
144 if ($gconfig{'ld_env'}) {
145         &print_tempfile(DRV, "$gconfig{'ld_env'}=$gconfig{'ld_path'}\n");
146         }
147 &print_tempfile(DRV, "PATH=$gconfig{'path'}\n");
148 &print_tempfile(DRV, "export $gconfig{'ld_env'} PATH\n");
149 if (!$_[1]->{'program'}) {
150         if ($config{'iface_arg'}) {
151                 for($i=0; $i<$config{'iface_arg'}-1; $i++) {
152                         &print_tempfile(DRV, "shift\n");
153                         }
154                 &print_tempfile(DRV, "cat \$* >/tmp/\$\$.smb\n");
155                 }
156         else { &print_tempfile(DRV, "cat >/tmp/\$\$.smb\n"); }
157         }
158 else {
159         &print_tempfile(DRV, "$_[1]->{'program'} \"\$1\" \"\$2\" \"\$3\" \"\$4\" ",
160                   "\"\$5\" \"\$6\" \"\$7\" \"\$8\" \"\$9\" ",
161                   "\"\$10\" \"\$11\" \"\$12\" \"\$13\" >/tmp/\$\$.smb\n");
162         &system_logged("chmod a+rx '$_[1]->{'program'}'");
163         }
164 &print_tempfile(DRV, "$config{'smbclient_path'} '//$_[1]->{'server'}/$_[1]->{'share'}' ",
165           $_[1]->{'pass'} ? $_[1]->{'pass'} : "-N",
166           $_[1]->{'user'} ? " -U $_[1]->{'user'}" : "",
167           $_[1]->{'workgroup'} ? " -W $_[1]->{'workgroup'}" : "",
168           " -c \"print /tmp/\$\$.smb\"\n");
169 &print_tempfile(DRV, "rm /tmp/\$\$.smb\n");
170 &close_tempfile(DRV);
171 if ($config{'iface_owner'}) {
172         &system_logged("chown '$config{'iface_owner'}' '$drv' >/dev/null 2>&1");
173         }
174 &system_logged("chmod '$config{'iface_perms'}' '$drv' >/dev/null 2>&1");
175 return $drv;
176 }
177
178 # create_hpnp_driver(&printer, &driver)
179 # Create an interface program that can print to a hpnp server using some
180 # interface program
181 sub create_hpnp_driver
182 {
183 local($drv, $prog);
184 &lock_file($drivers_directory);
185 mkdir($drivers_directory, 0755);
186 &unlock_file($drivers_directory);
187 $drv = "$drivers_directory/$_[0]->{'name'}.hpnp";
188
189 # Create script to call hpnp
190 &open_lock_tempfile(DRV, ">$drv");
191 &print_tempfile(DRV, "#!/bin/sh\n");
192 &print_tempfile(DRV, "# Name: $_[0]->{'name'}\n");
193 &print_tempfile(DRV, "# Server: $_[1]->{'server'}\n");
194 &print_tempfile(DRV, "# Port: $_[1]->{'port'}\n");
195 &print_tempfile(DRV, "# Program: $_[1]->{'program'}\n");
196 if ($gconfig{'ld_env'}) {
197         &print_tempfile(DRV, "$gconfig{'ld_env'}=$gconfig{'ld_path'}\n");
198         }
199 &print_tempfile(DRV, "PATH=$gconfig{'path'}\n");
200 &print_tempfile(DRV, "export $gconfig{'ld_env'} PATH\n");
201 if (!$_[1]->{'program'}) {
202         if ($config{'iface_arg'}) {
203                 for($i=0; $i<$config{'iface_arg'}-1; $i++) {
204                         &print_tempfile(DRV, "shift\n");
205                         }
206                 &print_tempfile(DRV, "cat \$* >/tmp/\$\$.hpnp\n");
207                 }
208         else { &print_tempfile(DRV, "cat >/tmp/\$\$.hpnp\n"); }
209         }
210 else {
211         &print_tempfile(DRV, "$_[1]->{'program'} \"\$1\" \"\$2\" \"\$3\" \"\$4\" ",
212                   "\"\$5\" \"\$6\" \"\$7\" \"\$8\" \"\$9\" ",
213                   "\"\$10\" \"\$11\" \"\$12\" \"\$13\" >/tmp/\$\$.hpnp\n");
214         &system_logged("chmod a+rx '$_[1]->{'program'}'");
215         }
216 &print_tempfile(DRV, "$config{'hpnp_path'} -x $_[1]->{'server'}",
217           $_[1]->{'port'} ? " -p $_[1]->{'port'}" : "",
218           " /tmp/\$\$.hpnp\n");
219 &print_tempfile(DRV, "rm /tmp/\$\$.hpnp\n");
220 &close_tempfile(DRV);
221 if ($config{'iface_owner'}) {
222         &system_logged("chown $config{'iface_owner'} $drv >/dev/null 2>&1");
223         }
224 &system_logged("chmod '$config{'iface_perms'}' '$drv' >/dev/null 2>&1");
225 &unlock_file($drv);
226 return $drv;
227 }
228
229 # is_webmin_driver(path)
230 # Returns a structure of driver information
231 sub is_webmin_driver
232 {
233 local($l, $i, $u, $desc);
234 if (!$_[0]) {
235         return { 'mode' => 0,
236                  'desc' => 'None' };
237         }
238 if (&has_ghostscript()) {
239         open(DRV, $_[0]);
240         for($i=0; $i<4; $i++) { $l .= <DRV>; }
241         close(DRV);
242         if ($l =~ /# Name: (.*)\n# Type: (.*)\n# DPI: (.*)\n/) {
243                 if ($2 eq 'uniprint') {
244                         local $upp = $3;
245                         foreach $u (&list_uniprint()) {
246                                 $desc = $u->[1] if ($u->[0] eq $upp);
247                                 }
248                         $desc =~ s/,.*$//;
249                         return { 'mode' => 3,
250                                  'upp' => $upp,
251                                  'desc' => $desc ? $desc : $upp };
252                         }
253                 else {
254                         return { 'type' => $2,
255                                  'dpi' => $3,
256                                  'mode' => 1,
257                                  'desc' => $3 ? "$2 ($3 DPI)" : $2 };
258                         }
259                 }
260         }
261 return { 'desc' => $_[0],
262          'prog' => $_[0],
263          'mode' => 2 };
264 }
265
266 # is_webmin_windows_driver(path)
267 # Returns a structure containing information about a windows driver, or undef
268 # Returns the server, share, username, password, workgroup, program
269 # if path is a webmin windows driver
270 sub is_webmin_windows_driver
271 {
272 local($i, $l);
273 if (!&has_smbclient()) { return undef; }
274 open(DRV, $_[0]);
275 for($i=0; $i<8; $i++) { $l .= <DRV>; }
276 close(DRV);
277 if ($l =~ /# Name: (.*)\n# Server: (.*)\n# Share: (.*)\n# User: (.*)\n# Password: (.*)\n# Workgroup: (.*)\n# Program: (.*)\n/) {
278         return { 'server' => $2,
279                  'share' => $3,
280                  'user' => $4,
281                  'pass' => $5,
282                  'workgroup' => $6,
283                  'program' => $7 };
284         }
285 elsif ($l =~ /# Name: (.*)\n# Server: (.*)\n# Share: (.*)\n# User: (.*)\n# Password: (.*)\n# Program: (.*)\n/) {
286         return { 'server' => $2,
287                  'share' => $3,
288                  'user' => $4,
289                  'pass' => $5,
290                  'program' => $7 };
291         }
292 else { return undef; }
293 }
294
295 # delete_webmin_driver(name)
296 # Delete the drivers for some printer
297 sub delete_webmin_driver
298 {
299 &lock_file("$drivers_directory/$_[0]");
300 &lock_file("$drivers_directory/$_[0].smb");
301 &lock_file("$drivers_directory/$_[0].hpnp");
302 unlink("$drivers_directory/$_[0]");
303 unlink("$drivers_directory/$_[0].smb");
304 unlink("$drivers_directory/$_[0].hpnp");
305 &unlock_file("$drivers_directory/$_[0]");
306 &unlock_file("$drivers_directory/$_[0].smb");
307 &unlock_file("$drivers_directory/$_[0].hpnp");
308 }
309
310 # is_hpnp_driver(path, &printer)
311 # Returns a structure of hpnp details if path is a webmin hpnp driver
312 sub is_hpnp_driver
313 {
314 local($i, $l);
315 if (!&has_hpnp()) { return undef; }
316 open(DRV, $_[0]);
317 for($i=0; $i<5; $i++) { $l .= <DRV>; }
318 close(DRV);
319 if ($l =~ /# Name: (.*)\n# Server: (.*)\n# Port: (.*)\n# Program: (.*)\n/) {
320         return { 'server' => $2,
321                  'port' => $3,
322                  'program' => $4 };
323         }
324 else { return undef; }
325 }
326
327 # webmin_driver_input(&printer, &driver)
328 sub webmin_driver_input
329 {
330 local ($prn, $drv) = @_;
331
332 printf "<tr> <td><input type=radio name=drv value=0 %s> %s</td>\n",
333         $drv->{'mode'} == 0 ? "checked" : "", $text{'webmin_none'};
334 print "<td>($text{'webmin_nonemsg'})</td> </tr>\n";
335
336 printf "<tr> <td><input type=radio name=drv value=2 %s> %s</td>\n",
337         $drv->{'mode'} == 2 ? "checked" : "", $text{'webmin_prog'};
338 printf "<td><input name=iface value=\"%s\" size=35></td> </tr>\n",
339         $drv->{'mode'} == 2 ? $drv->{'prog'} : "";
340
341 if (&has_ghostscript()) {
342         local $out = &backquote_command("$config{'gs_path'} -help 2>&1", 1);
343         if ($out =~ /Available devices:\n((\s+.*\n)+)/i) {
344                 print "<tr> <td valign=top>\n";
345                 printf "<input type=radio name=drv value=1 %s>\n",
346                         $drv->{'mode'} == 1 ? "checked" : "";
347                 print "$text{'webmin_driver'}</td> <td valign=top>";
348                 foreach $d (split(/\s+/, $1)) { $drvsupp{$d}++; }
349                 print "<select name=driver size=7>\n";
350                 foreach $d (&list_webmin_drivers()) {
351                         if ($drvsupp{$d->[0]}) {
352                                 printf "<option value='%s' %s>%s&nbsp;&nbsp;&nbsp;(%s)\n",
353                                     $d->[1],
354                                     $d->[1] eq $drv->{'type'} ? "selected" : "",
355                                     $d->[1], $d->[0];
356                                 }
357                         }
358                 print "</select>&nbsp;&nbsp;";
359                 print "<select name=dpi size=7>\n";
360                 printf "<option value=\"\" %s>Default\n",
361                         $drv->{'dpi'} ? "" : "selected";
362                 foreach $d (75, 100, 150, 200, 300, 600, 720, 1440) {
363                         printf "<option value=\"$d\" %s>$d DPI\n",
364                                 $drv->{'dpi'} == $d ? "selected" : "";
365                         }
366                 print "</select></td> </tr>\n";
367
368                 if ($drvsupp{'uniprint'}) {
369                         print "<tr> <td valign=top>\n";
370                         printf "<input type=radio name=drv value=3 %s>\n",
371                                 $drv->{'mode'} == 3 ? "checked" : "";
372                         print "$text{'webmin_uniprint'}</td> <td valign=top>";
373                         print "<select name=uniprint size=5>\n";
374                         foreach $u (&list_uniprint()) {
375                                 printf "<option value=%s %s>%s\n",
376                                     $u->[0],
377                                     $u->[0] eq $drv->{'upp'} ? 'selected' : '',
378                                     $u->[1];
379                                 }
380                         print "</select></td> </tr>\n";
381                         }
382                 }
383         else {
384                 print "<tr> <td colspan=2>",
385                       &text('webmin_edrivers', "<tt>$config{'gs_path'}</tt>"),
386                       "</td> </tr>\n";
387                 }
388         }
389 elsif ($config{'gs_path'}) {
390         print "<tr> <td colspan=2>",
391               &text('webmin_egs', "<tt>$config{'gs_path'}</tt>"),
392               "</td> </tr>\n";
393         }
394 return undef;
395 }
396
397 # parse_webmin_driver()
398 # Parse driver selection from %in and return a driver structure
399 sub parse_webmin_driver
400 {
401 if ($in{'drv'} == 0) {
402         return { 'mode' => 0 };
403         }
404 elsif ($in{'drv'} == 2) {
405         my @iface = split(/\s+/, $in{'iface'});
406         -x $iface[0] || &error(&text('webmin_edriver', $iface[0]));
407         return { 'mode' => 2,
408                  'program' => $in{'iface'} };
409         }
410 elsif ($in{'drv'} == 1) {
411         return { 'mode' => 1,
412                  'type' => $in{'driver'},
413                  'dpi' => $in{'dpi'} };
414         }
415 elsif ($in{'drv'} == 3) {
416         return { 'mode' => 3,
417                  'upp' => $in{'uniprint'} };
418         }
419 }
420
421
422
423 # list_webmin_drivers()
424 sub list_webmin_drivers
425 {
426 local(@rv, $_);
427 open(DRIVERS, "$module_root_directory/drivers");
428 while(<DRIVERS>) {
429         /^(\S+)\s+(.*)/;
430         push(@rv, [ $1, $2 ]);
431         }
432 close(DRIVERS);
433 return @rv;
434 }
435
436 # can_edit_printer(printer)
437 sub can_edit_printer
438 {
439 foreach $p (split(/\s+/, $access{'printers'})) {
440         return 1 if ($p eq '*' || $p eq $_[0]);
441         }
442 return 0;
443 }
444
445 # can_edit_jobs(printer, user)
446 sub can_edit_jobs
447 {
448 local $rv = 0;
449 if ($access{'cancel'} == 1) {
450         $rv = 1;
451         }
452 elsif ($access{'cancel'} == 0) {
453         $rv = 0;
454         }
455 else {
456         foreach $p (split(/\s+/, $access{'jobs'})) {
457                 $rv = 1 if ($p eq $_[0]);
458                 }
459         }
460 if ($rv) {
461         if ($access{'user'} eq '*') {
462                 return 1;
463                 }
464         elsif ($access{'user'} eq $_[1]) {
465                 return 1;
466                 }
467         elsif (!$access{'user'} && $remote_user eq $_[1]) {
468                 return 1;
469                 }
470         }
471 return 0;
472 }
473
474 # list_uniprint()
475 # Returns a list of uniprint drivers support by the installed ghostscript
476 sub list_uniprint
477 {
478 local (@rv, $f, $d);
479 local $out = &backquote_command("$config{'gs_path'} -help 2>&1", 1);
480 if ($out =~ /Search path:\n((\s+.*\n)+)/i) {
481         foreach $d (split(/\s+/, $1)) {
482                 next if ($d !~ /^\//);
483                 opendir(DIR, $d);
484                 while($f = readdir(DIR)) {
485                         next if ($f !~ /^(.*)\.upp$/);
486                         local $upp = $1;
487                         open(UPP, "$d/$f");
488                         local $line = <UPP>;
489                         close(UPP);
490                         next if ($line !~ /upModel="(.*)"/i);
491                         push(@rv, [ $upp, $1 ]);
492                         }
493                 closedir(DIR);
494                 }
495         }
496 return sort { $a->[0] cmp $b->[0] } @rv;
497 }
498
499 sub log_info
500 {
501 local ($drv, $wdrv, $hdrv);
502 if (!$webmin_windows_driver) {
503         $wdrv = &is_webmin_windows_driver($_[0]->{'iface'}, $_[0]);
504         }
505 $wdrv = &is_windows_driver($_[0]->{'iface'}, $_[0]) if (!$wdrv);
506 $hdrv = &is_hpnp_driver($_[0]->{'iface'}, $_[0]);
507 local $iface = $wdrv ? $wdrv->{'program'} :
508                $hdrv ? $hdrv->{'program'} : $_[0]->{'iface'};
509
510 if (!$webmin_print_driver) {
511         $drv = &is_webmin_driver($iface, $_[0]);
512         }
513 $drv = &is_driver($iface, $_[0])
514         if ($drv->{'mode'} == 0 || $drv->{'mode'} == 2);
515 $drv->{'desc'} =~ s/\([^\)]+\)$//;
516
517 return { 'driver' => $drv->{'desc'},
518          'mode' => $drv->{'mode'},
519          'dest' => $wdrv ? "\\\\$wdrv->{'server'}\\$wdrv->{'share'}" :
520                    $hdrv ? "HPNP $hdrv->{'server'}:$hdrv->{'port'}" :
521                    $_[0]->{'rhost'} ? "$_[0]->{'rhost'}:$_[0]->{'rqueue'}" :
522                    $_[0]->{'dhost'} ? "$_[0]->{'dhost'}:$_[0]->{'dport'}" :
523                    &dev_name($_[0]->{'dev'}) };
524 }
525
526 # parse_cups_ppd(file)
527 # Converts a CUPS-style .ppd file into a hash of names and values
528 sub parse_cups_ppd
529 {
530 local ($file) = @_;
531 local %ppd;
532 if ($file =~ /\.gz$/) {
533         open(PPD, "gunzip -c ".quotemeta($file)." |");
534         }
535 else {
536         open(PPD, $file);
537         }
538 while(<PPD>) {
539         if (/^\s*\*(\S+):\s*"(.*)"/ || /^\s*\*(\S+):\s*(\S+)/) {
540                 $ppd{$1} = $2;
541                 }
542         elsif (/^\s*\*(\S+)\s+(\S+)\/([^:]+):/) {
543                 $ppd{$1}->{$2} = $3 if (!defined($ppd{$1}->{$2}));
544                 }
545         }
546 close(PPD);
547 return \%ppd;
548 }
549
550 # list_cluster_servers()
551 # Returns a list of servers on which printers are managed
552 sub list_cluster_servers
553 {
554 &foreign_require("servers", "servers-lib.pl");
555 local %ids = map { $_, 1 } split(/\s+/, $config{'servers'});
556 return grep { $ids{$_->{'id'}} } &servers::list_servers();
557 }
558
559 # add_cluster_server(&server)
560 sub add_cluster_server
561 {
562 local @sids = split(/\s+/, $config{'servers'});
563 $config{'servers'} = join(" ", @sids, $_[0]->{'id'});
564 &save_module_config();
565 }
566
567 # delete_cluster_server(&server)
568 sub delete_cluster_server
569 {
570 local @sids = split(/\s+/, $config{'servers'});
571 $config{'servers'} = join(" ", grep { $_ != $_[0]->{'id'} } @sids);
572 &save_module_config();
573 }
574
575 # server_name(&server)
576 sub server_name
577 {
578 return $_[0]->{'desc'} ? $_[0]->{'desc'} : $_[0]->{'host'};
579 }
580
581 # save_printer_cluster(new, &printer, &driver, &connection, webmin-driver, mode)
582 # Creates or updates the specified printer on all cluster hosts, and returns a
583 # list of error messages
584 sub save_on_cluster
585 {
586 return ( ) if (!$config{'servers'});
587 return ( ) if (&is_readonly_mode());
588 local ($new, $prn, $drv, $conn, $webmin, $mode) = @_;
589 &remote_error_setup(\&slave_error_handler);
590 local $slave;
591 local @slaveerrs;
592 foreach $slave (&list_cluster_servers()) {
593         # Connect to server
594         $slave_error = undef;
595         &remote_foreign_require($slave, "lpadmin", "lpadmin-lib.pl");
596         if ($slave_error) {
597                 push(@slaveerrs, [ $slave, $slave_error ]);
598                 next;
599                 }
600
601         # Create the driver and the printer
602         local $err = &remote_foreign_call($slave,
603                 "lpadmin", "save_printer_and_driver",
604                 $new, $prn, $drv, $conn, $webmin, $mode);
605         if ($slave_error) {
606                 push(@slaveerrs, [ $slave, $slave_error ]);
607                 }
608         elsif ($err == 1) {
609                 push(@slaveerrs, [ $slave, &text('save_edup', $prn->{'name'}) ]);
610                 }
611         elsif ($err == 2) {
612                 push(@slaveerrs, [ $slave, $text{'save_evalid'} ]);
613                 }
614         elsif ($err == 3) {
615                 push(@slaveerrs, [ $slave, &text('save_egone', $prn->{'name'}) ]);
616                 }
617         }
618 return @slaveerrs;
619 }
620
621 # delete_on_cluster(&printer)
622 # Deletes the specified printer on all cluster hosts, and returns a list of
623 # error messages.
624 sub delete_on_cluster
625 {
626 return ( ) if (!$config{'servers'});
627 return ( ) if (&is_readonly_mode());
628 local ($prn) = @_;
629 &remote_error_setup(\&slave_error_handler);
630 local $slave;
631 local @slaveerrs;
632 foreach $slave (&list_cluster_servers()) {
633         # Connect to server
634         $slave_error = undef;
635         &remote_foreign_require($slave, "lpadmin", "lpadmin-lib.pl");
636         if ($slave_error) {
637                 push(@slaveerrs, [ $slave, $slave_error ]);
638                 next;
639                 }
640
641         # Call the delete function
642         local $err = &remote_foreign_call($slave,
643                 "lpadmin", "delete_printer_and_driver", $prn);
644         if ($slave_error) {
645                 push(@slaveerrs, [ $slave, $slave_error ]);
646                 }
647         elsif ($err == 3) {
648                 push(@slaveerrs, [ $slave, &text('save_egone', $prn->{'name'}) ]);
649                 }
650         }
651 return @slaveerrs;
652 }
653
654 # save_printer_and_driver(new, &printer, &driver, &connection, webmin-driver, mode)
655 # Attempts to setup or modify a printer and driver. Returns 0 if OK, 1 if the
656 # printer already exists, 2 if some print system error occurred, or 3 if it
657 # doesn't exist but should.
658 sub save_printer_and_driver
659 {
660 local ($new, $prn, $drv, $conn, $webmin, $mode) = @_;
661 if ($new && &get_printer($prn->{'name'})) {
662         return 1;
663         }
664 elsif (!$new && !&get_printer($prn->{'name'})) {
665         return 2;
666         }
667 local $dfunc = $webmin ? \&create_webmin_driver : \&create_driver;
668 if ($mode <= 2 || $mode == 5) {
669         # Device, file or LPR host
670         $prn->{'iface'} = &$dfunc($prn, $drv);
671         }
672 elsif ($mode == 3) {
673         # Windows server
674         $prn->{'dev'} = "/dev/null";
675         $prn->{'iface'} = $webmin ? &create_webmin_windows_driver($prn, $conn)
676                                   : &create_windows_driver($prn, $conn);
677         }
678 elsif ($mode == 4) {
679         # HPNP server
680         $prn->{'dev'} = "/dev/null";
681         $prn->{'iface'} = &create_hpnp_driver($prn, $conn);
682         }
683
684 # Call os-specific validation function
685 if (defined(&validate_printer)) {
686         local $err = &validate_printer($prn);
687         return 2 if ($err);
688         }
689
690 # Actually create or update it
691 if ($new) {
692         &create_printer($prn);
693         }
694 else {
695         &modify_printer($prn);
696         }
697 &system_logged("$config{'apply_cmd'} >/dev/null 2>&1 </dev/null")
698         if ($config{'apply_cmd'});
699 return 0;
700 }
701
702 # delete_printer_and_driver(&printer)
703 # Deletes a printer, returning 1 if it could not be found, or 0 if everything
704 # went OK.
705 sub delete_printer_and_driver
706 {
707 local ($prn) = @_;
708 &delete_printer($prn->{'name'});
709 &delete_driver($prn->{'name'});
710 &delete_webmin_driver($prn->{'name'});
711 }
712
713 sub slave_error_handler
714 {
715 $slave_error = $_[0];
716 }
717
718 # delete_from_acls(name)
719 # Remove some named printer from all ACLs
720 sub delete_from_acls
721 {
722 local ($name) = @_;
723 local $wusers;
724 &read_acl(undef, \%wusers);
725 foreach my $u (keys %wusers) {
726         my %uaccess = &get_module_acl($u);
727         if ($uaccess{'printers'} ne '*') {
728                 $uaccess{'printers'} =
729                         join(' ', grep { $_ ne $name }
730                                   split(/\s+/, $uaccess{'printers'}));
731                 &save_module_acl(\%uaccess, $u);
732                 }
733         }
734 }
735
736 1;
737