1# lpadmin-lib.pl 2# Functions for configuring and adding printers 3 4BEGIN { push(@INC, ".."); }; 5use WebminCore; 6&init_config(); 7do "$config{'print_style'}-lib.pl"; 8if ($config{'driver_style'}) { 9 do "$config{'driver_style'}-driver.pl"; 10 } 11else { 12 do "webmin-driver.pl"; 13 } 14%access = &get_module_acl(); 15 16$drivers_directory = "$module_config_directory/drivers"; 17 18# dev_name(file) 19sub dev_name 20{ 21local($i); 22for($i=0; $i<@device_files; $i++) { 23 if ($device_files[$i] eq $_[0]) { return $device_names[$i]; } 24 } 25return $_[0]; 26} 27 28# has_ghostscript() 29# Does this system have ghostscript installed? 30sub has_ghostscript 31{ 32return &has_command($config{'gs_path'}); 33} 34 35# has_smbclient() 36# Does this system have smbclient installed? 37sub has_smbclient 38{ 39return &has_command($config{'smbclient_path'}); 40} 41 42# has_hpnp() 43# Does this system have hpnp installed? 44sub has_hpnp 45{ 46return &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 52sub create_webmin_driver 53{ 54# check for non-driver 55if ($_[1]->{'mode'} == 0) { 56 return undef; 57 } 58elsif ($_[1]->{'mode'} == 2) { 59 return $_[1]->{'program'}; 60 } 61 62local($drv, $d, $gsdrv, $res, $perl); 63&lock_file($drivers_directory); 64mkdir($drivers_directory, 0755); 65&unlock_file($drivers_directory); 66$drv = "$drivers_directory/$_[0]->{'name'}"; 67 68# Find ghostscript driver 69if ($_[1]->{'mode'} == 3) { 70 $gsdrv = 'uniprint'; 71 } 72else { 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"); 88if ($gconfig{'ld_env'}) { 89 &print_tempfile(DRV, "$gconfig{'ld_env'}=$gconfig{'ld_path'}\n"); 90 } 91&print_tempfile(DRV, "PATH=$gconfig{'path'}\n"); 92if ($config{'gs_fontpath'}) { 93 &print_tempfile(DRV, "GS_FONTPATH=$config{'gs_fontpath'}\n"); 94 } 95if ($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(); 102if ($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 } 108else { 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); 116if ($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"); 120return $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 126sub create_webmin_windows_driver 127{ 128local($drv, $prog); 129&lock_file($drivers_directory); 130mkdir($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"); 144if ($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"); 149if (!$_[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 } 158else { 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); 171if ($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"); 175return $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 181sub create_hpnp_driver 182{ 183local($drv, $prog); 184&lock_file($drivers_directory); 185mkdir($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"); 196if ($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"); 201if (!$_[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 } 210else { 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); 221if ($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); 226return $drv; 227} 228 229# is_webmin_driver(path) 230# Returns a structure of driver information 231sub is_webmin_driver 232{ 233local($l, $i, $u, $desc); 234if (!$_[0]) { 235 return { 'mode' => 0, 236 'desc' => 'None' }; 237 } 238if (&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 } 261return { '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 270sub is_webmin_windows_driver 271{ 272local($i, $l); 273if (!&has_smbclient()) { return undef; } 274open(DRV, "<".$_[0]); 275for($i=0; $i<8; $i++) { $l .= <DRV>; } 276close(DRV); 277if ($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 } 285elsif ($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 } 292else { return undef; } 293} 294 295# delete_webmin_driver(name) 296# Delete the drivers for some printer 297sub delete_webmin_driver 298{ 299&lock_file("$drivers_directory/$_[0]"); 300&lock_file("$drivers_directory/$_[0].smb"); 301&lock_file("$drivers_directory/$_[0].hpnp"); 302unlink("$drivers_directory/$_[0]"); 303unlink("$drivers_directory/$_[0].smb"); 304unlink("$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 312sub is_hpnp_driver 313{ 314local($i, $l); 315if (!&has_hpnp()) { return undef; } 316open(DRV, "<".$_[0]); 317for($i=0; $i<5; $i++) { $l .= <DRV>; } 318close(DRV); 319if ($l =~ /# Name: (.*)\n# Server: (.*)\n# Port: (.*)\n# Program: (.*)\n/) { 320 return { 'server' => $2, 321 'port' => $3, 322 'program' => $4 }; 323 } 324else { return undef; } 325} 326 327# webmin_driver_input(&printer, &driver) 328sub webmin_driver_input 329{ 330local ($prn, $drv) = @_; 331 332printf "<tr> <td><input type=radio name=drv value=0 %s> %s</td>\n", 333 $drv->{'mode'} == 0 ? "checked" : "", $text{'webmin_none'}; 334print "<td>($text{'webmin_nonemsg'})</td> </tr>\n"; 335 336printf "<tr> <td><input type=radio name=drv value=2 %s> %s</td>\n", 337 $drv->{'mode'} == 2 ? "checked" : "", $text{'webmin_prog'}; 338printf "<td><input name=iface value=\"%s\" size=35></td> </tr>\n", 339 $drv->{'mode'} == 2 ? $drv->{'prog'} : ""; 340 341if (&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 (%s)</option>\n", 353 $d->[1], 354 $d->[1] eq $drv->{'type'} ? "selected" : "", 355 $d->[1], $d->[0]; 356 } 357 } 358 print "</select> "; 359 print "<select name=dpi size=7>\n"; 360 printf "<option value=\"\" %s>Default</option>\n", 361 $drv->{'dpi'} ? "" : "selected"; 362 foreach $d (75, 100, 150, 200, 300, 600, 720, 1440) { 363 printf "<option value=\"$d\" %s>$d DPI</option>\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</option>\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 } 389elsif ($config{'gs_path'}) { 390 print "<tr> <td colspan=2>", 391 &text('webmin_egs', "<tt>$config{'gs_path'}</tt>"), 392 "</td> </tr>\n"; 393 } 394return undef; 395} 396 397# parse_webmin_driver() 398# Parse driver selection from %in and return a driver structure 399sub parse_webmin_driver 400{ 401if ($in{'drv'} == 0) { 402 return { 'mode' => 0 }; 403 } 404elsif ($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 } 410elsif ($in{'drv'} == 1) { 411 return { 'mode' => 1, 412 'type' => $in{'driver'}, 413 'dpi' => $in{'dpi'} }; 414 } 415elsif ($in{'drv'} == 3) { 416 return { 'mode' => 3, 417 'upp' => $in{'uniprint'} }; 418 } 419} 420 421 422 423# list_webmin_drivers() 424sub list_webmin_drivers 425{ 426local(@rv, $_); 427open(DRIVERS, "<$module_root_directory/drivers"); 428while(<DRIVERS>) { 429 /^(\S+)\s+(.*)/; 430 push(@rv, [ $1, $2 ]); 431 } 432close(DRIVERS); 433return @rv; 434} 435 436# can_edit_printer(printer) 437sub can_edit_printer 438{ 439foreach $p (split(/\s+/, $access{'printers'})) { 440 return 1 if ($p eq '*' || $p eq $_[0]); 441 } 442return 0; 443} 444 445# can_edit_jobs(printer, user) 446sub can_edit_jobs 447{ 448local $rv = 0; 449if ($access{'cancel'} == 1) { 450 $rv = 1; 451 } 452elsif ($access{'cancel'} == 0) { 453 $rv = 0; 454 } 455else { 456 foreach $p (split(/\s+/, $access{'jobs'})) { 457 $rv = 1 if ($p eq $_[0]); 458 } 459 } 460if ($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 } 471return 0; 472} 473 474# list_uniprint() 475# Returns a list of uniprint drivers support by the installed ghostscript 476sub list_uniprint 477{ 478local (@rv, $f, $d); 479local $out = &backquote_command("$config{'gs_path'} -help 2>&1", 1); 480if ($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 } 496return sort { $a->[0] cmp $b->[0] } @rv; 497} 498 499sub log_info 500{ 501local ($drv, $wdrv, $hdrv); 502if (!$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]); 507local $iface = $wdrv ? $wdrv->{'program'} : 508 $hdrv ? $hdrv->{'program'} : $_[0]->{'iface'}; 509 510if (!$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 517return { '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 528sub parse_cups_ppd 529{ 530local ($file) = @_; 531local %ppd; 532if ($file =~ /\.gz$/) { 533 open(PPD, "gunzip -c ".quotemeta($file)." |"); 534 } 535else { 536 open(PPD, "<".$file); 537 } 538while(<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 } 546close(PPD); 547return \%ppd; 548} 549 550# list_cluster_servers() 551# Returns a list of servers on which printers are managed 552sub list_cluster_servers 553{ 554&foreign_require("servers", "servers-lib.pl"); 555local %ids = map { $_, 1 } split(/\s+/, $config{'servers'}); 556return grep { $ids{$_->{'id'}} } &servers::list_servers(); 557} 558 559# add_cluster_server(&server) 560sub add_cluster_server 561{ 562local @sids = split(/\s+/, $config{'servers'}); 563$config{'servers'} = join(" ", @sids, $_[0]->{'id'}); 564&save_module_config(); 565} 566 567# delete_cluster_server(&server) 568sub delete_cluster_server 569{ 570local @sids = split(/\s+/, $config{'servers'}); 571$config{'servers'} = join(" ", grep { $_ != $_[0]->{'id'} } @sids); 572&save_module_config(); 573} 574 575# server_name(&server) 576sub server_name 577{ 578return $_[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 584sub save_on_cluster 585{ 586return ( ) if (!$config{'servers'}); 587return ( ) if (&is_readonly_mode()); 588local ($new, $prn, $drv, $conn, $webmin, $mode) = @_; 589&remote_error_setup(\&slave_error_handler); 590local $slave; 591local @slaveerrs; 592foreach $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 } 618return @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. 624sub delete_on_cluster 625{ 626return ( ) if (!$config{'servers'}); 627return ( ) if (&is_readonly_mode()); 628local ($prn) = @_; 629&remote_error_setup(\&slave_error_handler); 630local $slave; 631local @slaveerrs; 632foreach $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 } 651return @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. 658sub save_printer_and_driver 659{ 660local ($new, $prn, $drv, $conn, $webmin, $mode) = @_; 661if ($new && &get_printer($prn->{'name'})) { 662 return 1; 663 } 664elsif (!$new && !&get_printer($prn->{'name'})) { 665 return 2; 666 } 667local $dfunc = $webmin ? \&create_webmin_driver : \&create_driver; 668if ($mode <= 2 || $mode == 5) { 669 # Device, file or LPR host 670 $prn->{'iface'} = &$dfunc($prn, $drv); 671 } 672elsif ($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 } 678elsif ($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 685if (defined(&validate_printer)) { 686 local $err = &validate_printer($prn); 687 return 2 if ($err); 688 } 689 690# Actually create or update it 691if ($new) { 692 &create_printer($prn); 693 } 694else { 695 &modify_printer($prn); 696 } 697&system_logged("$config{'apply_cmd'} >/dev/null 2>&1 </dev/null") 698 if ($config{'apply_cmd'}); 699return 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. 705sub delete_printer_and_driver 706{ 707local ($prn) = @_; 708&delete_printer($prn->{'name'}); 709&delete_driver($prn->{'name'}); 710&delete_webmin_driver($prn->{'name'}); 711} 712 713sub slave_error_handler 714{ 715$slave_error = $_[0]; 716} 717 718# delete_from_acls(name) 719# Remove some named printer from all ACLs 720sub delete_from_acls 721{ 722local ($name) = @_; 723local $wusers; 724&read_acl(undef, \%wusers); 725foreach 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 7361; 737 738