1 /* 2 * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.print; 27 28 import java.io.BufferedReader; 29 import java.io.FileInputStream; 30 import java.io.InputStream; 31 import java.io.InputStreamReader; 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.Vector; 35 import java.security.AccessController; 36 import java.security.PrivilegedActionException; 37 import java.security.PrivilegedExceptionAction; 38 import javax.print.DocFlavor; 39 import javax.print.MultiDocPrintService; 40 import javax.print.PrintService; 41 import javax.print.PrintServiceLookup; 42 import javax.print.attribute.Attribute; 43 import javax.print.attribute.AttributeSet; 44 import javax.print.attribute.HashPrintRequestAttributeSet; 45 import javax.print.attribute.HashPrintServiceAttributeSet; 46 import javax.print.attribute.PrintRequestAttribute; 47 import javax.print.attribute.PrintRequestAttributeSet; 48 import javax.print.attribute.PrintServiceAttribute; 49 import javax.print.attribute.PrintServiceAttributeSet; 50 import javax.print.attribute.standard.PrinterName; 51 import javax.print.attribute.standard.PrinterURI; 52 import java.io.File; 53 import java.io.FileReader; 54 import java.net.URL; 55 import java.nio.file.Files; 56 57 /* 58 * Remind: This class uses solaris commands. We also need a linux 59 * version 60 */ 61 public class PrintServiceLookupProvider extends PrintServiceLookup 62 implements BackgroundServiceLookup, Runnable { 63 64 /* Remind: the current implementation is static, as its assumed 65 * its preferable to minimize creation of PrintService instances. 66 * Later we should add logic to add/remove services on the fly which 67 * will take a hit of needing to regather the list of services. 68 */ 69 private String defaultPrinter; 70 private PrintService defaultPrintService; 71 private PrintService[] printServices; /* includes the default printer */ 72 private Vector<BackgroundLookupListener> lookupListeners = null; 73 private static String debugPrefix = "PrintServiceLookupProvider>> "; 74 private static boolean pollServices = true; 75 private static final int DEFAULT_MINREFRESH = 120; // 2 minutes 76 private static int minRefreshTime = DEFAULT_MINREFRESH; 77 78 79 static String osname; 80 81 // List of commands used to deal with the printer queues on AIX 82 String[] lpNameComAix = { 83 "/usr/bin/lsallq", 84 "/usr/bin/lpstat -W -p|/usr/bin/expand|/usr/bin/cut -f1 -d' '", 85 "/usr/bin/lpstat -W -d|/usr/bin/expand|/usr/bin/cut -f1 -d' '", 86 "/usr/bin/lpstat -W -v" 87 }; 88 private static final int aix_lsallq = 0; 89 private static final int aix_lpstat_p = 1; 90 private static final int aix_lpstat_d = 2; 91 private static final int aix_lpstat_v = 3; 92 private static int aix_defaultPrinterEnumeration = aix_lsallq; 93 94 static { 95 /* The system property "sun.java2d.print.polling" 96 * can be used to force the printing code to poll or not poll 97 * for PrintServices. 98 */ 99 String pollStr = java.security.AccessController.doPrivileged( 100 new sun.security.action.GetPropertyAction("sun.java2d.print.polling")); 101 102 if (pollStr != null) { 103 if (pollStr.equalsIgnoreCase("true")) { 104 pollServices = true; 105 } else if (pollStr.equalsIgnoreCase("false")) { 106 pollServices = false; 107 } 108 } 109 110 /* The system property "sun.java2d.print.minRefreshTime" 111 * can be used to specify minimum refresh time (in seconds) 112 * for polling PrintServices. The default is 120. 113 */ 114 String refreshTimeStr = java.security.AccessController.doPrivileged( 115 new sun.security.action.GetPropertyAction( 116 "sun.java2d.print.minRefreshTime")); 117 118 if (refreshTimeStr != null) { 119 try { 120 minRefreshTime = (Integer.valueOf(refreshTimeStr)).intValue(); 121 } catch (NumberFormatException e) { 122 } 123 if (minRefreshTime < DEFAULT_MINREFRESH) { 124 minRefreshTime = DEFAULT_MINREFRESH; 125 } 126 } 127 128 osname = java.security.AccessController.doPrivileged( 129 new sun.security.action.GetPropertyAction("os.name")); 130 131 /* The system property "sun.java2d.print.aix.lpstat" 132 * can be used to force the usage of 'lpstat -p' to enumerate all 133 * printer queues. By default we use 'lsallq', because 'lpstat -p' can 134 * take lots of time if thousands of printers are attached to a server. 135 */ 136 if (isAIX()) { 137 String aixPrinterEnumerator = java.security.AccessController.doPrivileged( 138 new sun.security.action.GetPropertyAction("sun.java2d.print.aix.lpstat")); 139 140 if (aixPrinterEnumerator != null) { 141 if (aixPrinterEnumerator.equalsIgnoreCase("lpstat")) { 142 aix_defaultPrinterEnumeration = aix_lpstat_p; 143 } else if (aixPrinterEnumerator.equalsIgnoreCase("lsallq")) { 144 aix_defaultPrinterEnumeration = aix_lsallq; 145 } 146 } 147 } 148 } 149 150 static boolean isMac() { 151 return osname.startsWith("Mac"); 152 } 153 154 static boolean isSysV() { 155 return osname.equals("SunOS"); 156 } 157 158 static boolean isLinux() { 159 return (osname.equals("Linux")); 160 } 161 162 static boolean isBSD() { 163 return (osname.equals("Linux") || 164 osname.contains("OS X")); 165 } 166 167 static boolean isAIX() { 168 return osname.equals("AIX"); 169 } 170 171 static final int UNINITIALIZED = -1; 172 static final int BSD_LPD = 0; 173 static final int BSD_LPD_NG = 1; 174 175 static int cmdIndex = UNINITIALIZED; 176 177 String[] lpcFirstCom = { 178 "/usr/sbin/lpc status | grep : | sed -ne '1,1 s/://p'", 179 "/usr/sbin/lpc status | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'" 180 }; 181 182 String[] lpcAllCom = { 183 "/usr/sbin/lpc status all | grep : | sed -e 's/://'", 184 "/usr/sbin/lpc status all | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}' | sort" 185 }; 186 187 String[] lpcNameCom = { 188 "| grep : | sed -ne 's/://p'", 189 "| grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'" 190 }; 191 192 193 static int getBSDCommandIndex() { 194 String command = "/usr/sbin/lpc status all"; 195 String[] names = execCmd(command); 196 197 if ((names == null) || (names.length == 0)) { 198 return BSD_LPD_NG; 199 } 200 201 for (int i=0; i<names.length; i++) { 202 if (names[i].indexOf('@') != -1) { 203 return BSD_LPD_NG; 204 } 205 } 206 207 return BSD_LPD; 208 } 209 210 211 public PrintServiceLookupProvider() { 212 // start the printer listener thread 213 if (pollServices) { 214 Thread thr = new Thread(null, new PrinterChangeListener(), 215 "PrinterListener", 0, false); 216 thr.setDaemon(true); 217 thr.start(); 218 IPPPrintService.debug_println(debugPrefix+"polling turned on"); 219 } 220 } 221 222 /* Want the PrintService which is default print service to have 223 * equality of reference with the equivalent in list of print services 224 * This isn't required by the API and there's a risk doing this will 225 * lead people to assume its guaranteed. 226 */ 227 public synchronized PrintService[] getPrintServices() { 228 SecurityManager security = System.getSecurityManager(); 229 if (security != null) { 230 security.checkPrintJobAccess(); 231 } 232 233 if (printServices == null || !pollServices) { 234 refreshServices(); 235 } 236 if (printServices == null) { 237 return new PrintService[0]; 238 } else { 239 return printServices.clone(); 240 } 241 } 242 243 private int addPrintServiceToList(ArrayList<PrintService> printerList, PrintService ps) { 244 int index = printerList.indexOf(ps); 245 // Check if PrintService with same name is already in the list. 246 if (CUPSPrinter.isCupsRunning() && index != -1) { 247 // Bug in Linux: Duplicate entry of a remote printer 248 // and treats it as local printer but it is returning wrong 249 // information when queried using IPP. Workaround is to remove it. 250 // Even CUPS ignores these entries as shown in lpstat or using 251 // their web configuration. 252 PrinterURI uri = ps.getAttribute(PrinterURI.class); 253 if (uri.getURI().getHost().equals("localhost")) { 254 IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, ignoring the new local printer: "+ps); 255 return index; // Do not add this. 256 } 257 PrintService oldPS = printerList.get(index); 258 uri = oldPS.getAttribute(PrinterURI.class); 259 if (uri.getURI().getHost().equals("localhost")) { 260 IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, removing existing local printer: "+oldPS); 261 printerList.remove(oldPS); 262 } else { 263 return index; 264 } 265 } 266 printerList.add(ps); 267 return (printerList.size() - 1); 268 } 269 270 271 // refreshes "printServices" 272 public synchronized void refreshServices() { 273 /* excludes the default printer */ 274 String[] printers = null; // array of printer names 275 String[] printerURIs = null; //array of printer URIs 276 277 try { 278 getDefaultPrintService(); 279 } catch (Throwable t) { 280 IPPPrintService.debug_println(debugPrefix+ 281 "Exception getting default printer : " + t); 282 } 283 if (CUPSPrinter.isCupsRunning()) { 284 try { 285 printerURIs = CUPSPrinter.getAllPrinters(); 286 IPPPrintService.debug_println("CUPS URIs = " + printerURIs); 287 if (printerURIs != null) { 288 for (int p = 0; p < printerURIs.length; p++) { 289 IPPPrintService.debug_println("URI="+printerURIs[p]); 290 } 291 } 292 } catch (Throwable t) { 293 IPPPrintService.debug_println(debugPrefix+ 294 "Exception getting all CUPS printers : " + t); 295 } 296 if ((printerURIs != null) && (printerURIs.length > 0)) { 297 printers = new String[printerURIs.length]; 298 for (int i=0; i<printerURIs.length; i++) { 299 int lastIndex = printerURIs[i].lastIndexOf("/"); 300 printers[i] = printerURIs[i].substring(lastIndex+1); 301 } 302 } 303 } else { 304 if (isMac() || isSysV()) { 305 printers = getAllPrinterNamesSysV(); 306 } else if (isAIX()) { 307 printers = getAllPrinterNamesAIX(); 308 } else { //BSD 309 printers = getAllPrinterNamesBSD(); 310 } 311 } 312 313 if (printers == null) { 314 if (defaultPrintService != null) { 315 printServices = new PrintService[1]; 316 printServices[0] = defaultPrintService; 317 } else { 318 printServices = null; 319 } 320 return; 321 } 322 323 ArrayList<PrintService> printerList = new ArrayList<>(); 324 int defaultIndex = -1; 325 for (int p=0; p<printers.length; p++) { 326 if (printers[p] == null) { 327 continue; 328 } 329 if ((defaultPrintService != null) 330 && printers[p].equals(getPrinterDestName(defaultPrintService))) { 331 defaultIndex = addPrintServiceToList(printerList, defaultPrintService); 332 } else { 333 if (printServices == null) { 334 IPPPrintService.debug_println(debugPrefix+ 335 "total# of printers = "+printers.length); 336 337 if (CUPSPrinter.isCupsRunning()) { 338 try { 339 addPrintServiceToList(printerList, 340 new IPPPrintService(printers[p], 341 printerURIs[p], 342 true)); 343 } catch (Exception e) { 344 IPPPrintService.debug_println(debugPrefix+ 345 " getAllPrinters Exception "+ 346 e); 347 348 } 349 } else { 350 printerList.add(new UnixPrintService(printers[p])); 351 } 352 } else { 353 int j; 354 for (j=0; j<printServices.length; j++) { 355 if (printServices[j] != null) { 356 if (printers[p].equals(getPrinterDestName(printServices[j]))) { 357 printerList.add(printServices[j]); 358 printServices[j] = null; 359 break; 360 } 361 } 362 } 363 364 if (j == printServices.length) { // not found? 365 if (CUPSPrinter.isCupsRunning()) { 366 try { 367 addPrintServiceToList(printerList, 368 new IPPPrintService(printers[p], 369 printerURIs[p], 370 true)); 371 } catch (Exception e) { 372 IPPPrintService.debug_println(debugPrefix+ 373 " getAllPrinters Exception "+ 374 e); 375 376 } 377 } else { 378 printerList.add(new UnixPrintService(printers[p])); 379 } 380 } 381 } 382 } 383 } 384 385 // Look for deleted services and invalidate these 386 if (printServices != null) { 387 for (int j=0; j < printServices.length; j++) { 388 if ((printServices[j] instanceof UnixPrintService) && 389 (!printServices[j].equals(defaultPrintService))) { 390 ((UnixPrintService)printServices[j]).invalidateService(); 391 } 392 } 393 } 394 395 //if defaultService is not found in printerList 396 if (defaultIndex == -1 && defaultPrintService != null) { 397 defaultIndex = addPrintServiceToList(printerList, defaultPrintService); 398 } 399 400 printServices = printerList.toArray(new PrintService[] {}); 401 402 // swap default with the first in the list 403 if (defaultIndex > 0) { 404 PrintService saveService = printServices[0]; 405 printServices[0] = printServices[defaultIndex]; 406 printServices[defaultIndex] = saveService; 407 } 408 } 409 410 private boolean matchesAttributes(PrintService service, 411 PrintServiceAttributeSet attributes) { 412 413 Attribute [] attrs = attributes.toArray(); 414 for (int i=0; i<attrs.length; i++) { 415 @SuppressWarnings("unchecked") 416 Attribute serviceAttr 417 = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory()); 418 if (serviceAttr == null || !serviceAttr.equals(attrs[i])) { 419 return false; 420 } 421 } 422 return true; 423 } 424 425 /* This checks for validity of the printer name before passing as 426 * parameter to a shell command. 427 */ 428 private boolean checkPrinterName(String s) { 429 char c; 430 431 for (int i=0; i < s.length(); i++) { 432 c = s.charAt(i); 433 if (Character.isLetterOrDigit(c) || 434 c == '-' || c == '_' || c == '.' || c == '/') { 435 continue; 436 } else { 437 return false; 438 } 439 } 440 return true; 441 } 442 443 /* 444 * Gets the printer name compatible with the list of printers returned by 445 * the system when we query default or all the available printers. 446 */ 447 private String getPrinterDestName(PrintService ps) { 448 if (isMac()) { 449 return ((IPPPrintService)ps).getDest(); 450 } 451 return ps.getName(); 452 } 453 454 /* On a network with many (hundreds) of network printers, it 455 * can save several seconds if you know all you want is a particular 456 * printer, to ask for that printer rather than retrieving all printers. 457 */ 458 private PrintService getServiceByName(PrinterName nameAttr) { 459 String name = nameAttr.getValue(); 460 if (name == null || name.isEmpty() || !checkPrinterName(name)) { 461 return null; 462 } 463 /* check if all printers are already available */ 464 if (printServices != null) { 465 for (PrintService printService : printServices) { 466 PrinterName printerName = printService.getAttribute(PrinterName.class); 467 if (printerName.getValue().equals(name)) { 468 return printService; 469 } 470 } 471 } 472 /* take CUPS into account first */ 473 if (CUPSPrinter.isCupsRunning()) { 474 try { 475 return new IPPPrintService(name, 476 new URL("http://"+ 477 CUPSPrinter.getServer()+":"+ 478 CUPSPrinter.getPort()+"/"+ 479 name)); 480 } catch (Exception e) { 481 IPPPrintService.debug_println(debugPrefix+ 482 " getServiceByName Exception "+ 483 e); 484 } 485 } 486 /* fallback if nothing not having a printer at this point */ 487 PrintService printer = null; 488 if (isMac() || isSysV()) { 489 printer = getNamedPrinterNameSysV(name); 490 } else if (isAIX()) { 491 printer = getNamedPrinterNameAIX(name); 492 } else { 493 printer = getNamedPrinterNameBSD(name); 494 } 495 return printer; 496 } 497 498 private PrintService[] 499 getPrintServices(PrintServiceAttributeSet serviceSet) { 500 501 if (serviceSet == null || serviceSet.isEmpty()) { 502 return getPrintServices(); 503 } 504 505 /* Typically expect that if a service attribute is specified that 506 * its a printer name and there ought to be only one match. 507 * Directly retrieve that service and confirm 508 * that it meets the other requirements. 509 * If printer name isn't mentioned then go a slow path checking 510 * all printers if they meet the reqiremements. 511 */ 512 PrintService[] services; 513 PrinterName name = (PrinterName)serviceSet.get(PrinterName.class); 514 PrintService defService; 515 if (name != null && (defService = getDefaultPrintService()) != null) { 516 /* To avoid execing a unix command see if the client is asking 517 * for the default printer by name, since we already have that 518 * initialised. 519 */ 520 521 PrinterName defName = defService.getAttribute(PrinterName.class); 522 523 if (defName != null && name.equals(defName)) { 524 if (matchesAttributes(defService, serviceSet)) { 525 services = new PrintService[1]; 526 services[0] = defService; 527 return services; 528 } else { 529 return new PrintService[0]; 530 } 531 } else { 532 /* Its not the default service */ 533 PrintService service = getServiceByName(name); 534 if (service != null && 535 matchesAttributes(service, serviceSet)) { 536 services = new PrintService[1]; 537 services[0] = service; 538 return services; 539 } else { 540 return new PrintService[0]; 541 } 542 } 543 } else { 544 /* specified service attributes don't include a name.*/ 545 Vector<PrintService> matchedServices = new Vector<>(); 546 services = getPrintServices(); 547 for (int i = 0; i< services.length; i++) { 548 if (matchesAttributes(services[i], serviceSet)) { 549 matchedServices.add(services[i]); 550 } 551 } 552 services = new PrintService[matchedServices.size()]; 553 for (int i = 0; i< services.length; i++) { 554 services[i] = matchedServices.elementAt(i); 555 } 556 return services; 557 } 558 } 559 560 /* 561 * If service attributes are specified then there must be additional 562 * filtering. 563 */ 564 public PrintService[] getPrintServices(DocFlavor flavor, 565 AttributeSet attributes) { 566 SecurityManager security = System.getSecurityManager(); 567 if (security != null) { 568 security.checkPrintJobAccess(); 569 } 570 PrintRequestAttributeSet requestSet = null; 571 PrintServiceAttributeSet serviceSet = null; 572 573 if (attributes != null && !attributes.isEmpty()) { 574 575 requestSet = new HashPrintRequestAttributeSet(); 576 serviceSet = new HashPrintServiceAttributeSet(); 577 578 Attribute[] attrs = attributes.toArray(); 579 for (int i=0; i<attrs.length; i++) { 580 if (attrs[i] instanceof PrintRequestAttribute) { 581 requestSet.add(attrs[i]); 582 } else if (attrs[i] instanceof PrintServiceAttribute) { 583 serviceSet.add(attrs[i]); 584 } 585 } 586 } 587 588 PrintService[] services = getPrintServices(serviceSet); 589 if (services.length == 0) { 590 return services; 591 } 592 593 if (CUPSPrinter.isCupsRunning()) { 594 ArrayList<PrintService> matchingServices = new ArrayList<>(); 595 for (int i=0; i<services.length; i++) { 596 try { 597 if (services[i]. 598 getUnsupportedAttributes(flavor, requestSet) == null) { 599 matchingServices.add(services[i]); 600 } 601 } catch (IllegalArgumentException e) { 602 } 603 } 604 services = new PrintService[matchingServices.size()]; 605 return matchingServices.toArray(services); 606 607 } else { 608 // We only need to compare 1 PrintService because all 609 // UnixPrintServices are the same anyway. We will not use 610 // default PrintService because it might be null. 611 PrintService service = services[0]; 612 if ((flavor == null || 613 service.isDocFlavorSupported(flavor)) && 614 service.getUnsupportedAttributes(flavor, requestSet) == null) 615 { 616 return services; 617 } else { 618 return new PrintService[0]; 619 } 620 } 621 } 622 623 /* 624 * return empty array as don't support multi docs 625 */ 626 public MultiDocPrintService[] 627 getMultiDocPrintServices(DocFlavor[] flavors, 628 AttributeSet attributes) { 629 SecurityManager security = System.getSecurityManager(); 630 if (security != null) { 631 security.checkPrintJobAccess(); 632 } 633 return new MultiDocPrintService[0]; 634 } 635 636 637 public synchronized PrintService getDefaultPrintService() { 638 SecurityManager security = System.getSecurityManager(); 639 if (security != null) { 640 security.checkPrintJobAccess(); 641 } 642 643 // clear defaultPrintService 644 defaultPrintService = null; 645 String psuri = null; 646 647 IPPPrintService.debug_println("isRunning ? "+ 648 (CUPSPrinter.isCupsRunning())); 649 if (CUPSPrinter.isCupsRunning()) { 650 String[] printerInfo = CUPSPrinter.getDefaultPrinter(); 651 if (printerInfo != null && printerInfo.length >= 2) { 652 defaultPrinter = printerInfo[0]; 653 psuri = printerInfo[1]; 654 } 655 } else { 656 if (isMac() || isSysV()) { 657 defaultPrinter = getDefaultPrinterNameSysV(); 658 } else if (isAIX()) { 659 defaultPrinter = getDefaultPrinterNameAIX(); 660 } else { 661 defaultPrinter = getDefaultPrinterNameBSD(); 662 } 663 } 664 if (defaultPrinter == null) { 665 return null; 666 } 667 defaultPrintService = null; 668 if (printServices != null) { 669 for (int j=0; j<printServices.length; j++) { 670 if (defaultPrinter.equals(getPrinterDestName(printServices[j]))) { 671 defaultPrintService = printServices[j]; 672 break; 673 } 674 } 675 } 676 if (defaultPrintService == null) { 677 if (CUPSPrinter.isCupsRunning()) { 678 try { 679 PrintService defaultPS; 680 if ((psuri != null) && !psuri.startsWith("file")) { 681 defaultPS = new IPPPrintService(defaultPrinter, 682 psuri, true); 683 } else { 684 defaultPS = new IPPPrintService(defaultPrinter, 685 new URL("http://"+ 686 CUPSPrinter.getServer()+":"+ 687 CUPSPrinter.getPort()+"/"+ 688 defaultPrinter)); 689 } 690 defaultPrintService = defaultPS; 691 } catch (Exception e) { 692 } 693 } else { 694 defaultPrintService = new UnixPrintService(defaultPrinter); 695 } 696 } 697 698 return defaultPrintService; 699 } 700 701 public synchronized void 702 getServicesInbackground(BackgroundLookupListener listener) { 703 if (printServices != null) { 704 listener.notifyServices(printServices); 705 } else { 706 if (lookupListeners == null) { 707 lookupListeners = new Vector<>(); 708 lookupListeners.add(listener); 709 Thread lookupThread = new Thread(this); 710 lookupThread.start(); 711 } else { 712 lookupListeners.add(listener); 713 } 714 } 715 } 716 717 /* This method isn't used in most cases because we rely on code in 718 * javax.print.PrintServiceLookup. This is needed just for the cases 719 * where those interfaces are by-passed. 720 */ 721 private PrintService[] copyOf(PrintService[] inArr) { 722 if (inArr == null || inArr.length == 0) { 723 return inArr; 724 } else { 725 PrintService []outArr = new PrintService[inArr.length]; 726 System.arraycopy(inArr, 0, outArr, 0, inArr.length); 727 return outArr; 728 } 729 } 730 731 public void run() { 732 PrintService[] services = getPrintServices(); 733 synchronized (this) { 734 BackgroundLookupListener listener; 735 for (int i=0; i<lookupListeners.size(); i++) { 736 listener = lookupListeners.elementAt(i); 737 listener.notifyServices(copyOf(services)); 738 } 739 lookupListeners = null; 740 } 741 } 742 743 private String getDefaultPrinterNameBSD() { 744 if (cmdIndex == UNINITIALIZED) { 745 cmdIndex = getBSDCommandIndex(); 746 } 747 String[] names = execCmd(lpcFirstCom[cmdIndex]); 748 if (names == null || names.length == 0) { 749 return null; 750 } 751 752 if ((cmdIndex==BSD_LPD_NG) && 753 (names[0].startsWith("missingprinter"))) { 754 return null; 755 } 756 return names[0]; 757 } 758 759 private PrintService getNamedPrinterNameBSD(String name) { 760 if (cmdIndex == UNINITIALIZED) { 761 cmdIndex = getBSDCommandIndex(); 762 } 763 String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex]; 764 String[] result = execCmd(command); 765 766 if (result == null || !(result[0].equals(name))) { 767 return null; 768 } 769 return new UnixPrintService(name); 770 } 771 772 private String[] getAllPrinterNamesBSD() { 773 if (cmdIndex == UNINITIALIZED) { 774 cmdIndex = getBSDCommandIndex(); 775 } 776 String[] names = execCmd(lpcAllCom[cmdIndex]); 777 if (names == null || names.length == 0) { 778 return null; 779 } 780 return names; 781 } 782 783 static String getDefaultPrinterNameSysV() { 784 String defaultPrinter = "lp"; 785 String command = "/usr/bin/lpstat -d"; 786 787 String [] names = execCmd(command); 788 if (names == null || names.length == 0) { 789 return defaultPrinter; 790 } else { 791 int index = names[0].indexOf(":"); 792 if (index == -1 || (names[0].length() <= index+1)) { 793 return null; 794 } else { 795 String name = names[0].substring(index+1).trim(); 796 if (name.length() == 0) { 797 return null; 798 } else { 799 return name; 800 } 801 } 802 } 803 } 804 805 private PrintService getNamedPrinterNameSysV(String name) { 806 807 String command = "/usr/bin/lpstat -v " + name; 808 String []result = execCmd(command); 809 810 if (result == null || result[0].indexOf("unknown printer") > 0) { 811 return null; 812 } else { 813 return new UnixPrintService(name); 814 } 815 } 816 817 private String[] getAllPrinterNamesSysV() { 818 String defaultPrinter = "lp"; 819 String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort"; 820 821 String [] names = execCmd(command); 822 ArrayList<String> printerNames = new ArrayList<>(); 823 for (int i=0; i < names.length; i++) { 824 if (!names[i].equals("_default") && 825 !names[i].equals(defaultPrinter) && 826 !names[i].isEmpty()) { 827 printerNames.add(names[i]); 828 } 829 } 830 return printerNames.toArray(new String[printerNames.size()]); 831 } 832 833 private String getDefaultPrinterNameAIX() { 834 String[] names = execCmd(lpNameComAix[aix_lpstat_d]); 835 // Remove headers and bogus entries added by remote printers. 836 names = UnixPrintService.filterPrinterNamesAIX(names); 837 if (names == null || names.length != 1) { 838 // No default printer found 839 return null; 840 } else { 841 return names[0]; 842 } 843 } 844 845 private PrintService getNamedPrinterNameAIX(String name) { 846 // On AIX there should be no blank after '-v'. 847 String[] result = execCmd(lpNameComAix[aix_lpstat_v] + name); 848 // Remove headers and bogus entries added by remote printers. 849 result = UnixPrintService.filterPrinterNamesAIX(result); 850 if (result == null || result.length != 1) { 851 return null; 852 } else { 853 return new UnixPrintService(name); 854 } 855 } 856 857 private String[] getAllPrinterNamesAIX() { 858 // Determine all printers of the system. 859 String [] names = execCmd(lpNameComAix[aix_defaultPrinterEnumeration]); 860 861 // Remove headers and bogus entries added by remote printers. 862 names = UnixPrintService.filterPrinterNamesAIX(names); 863 864 ArrayList<String> printerNames = new ArrayList<String>(); 865 for ( int i=0; i < names.length; i++) { 866 printerNames.add(names[i]); 867 } 868 return printerNames.toArray(new String[printerNames.size()]); 869 } 870 871 static String[] execCmd(final String command) { 872 ArrayList<String> results = null; 873 try { 874 final String[] cmd = new String[3]; 875 if (isSysV() || isAIX()) { 876 cmd[0] = "/usr/bin/sh"; 877 cmd[1] = "-c"; 878 cmd[2] = "env LC_ALL=C " + command; 879 } else { 880 cmd[0] = "/bin/sh"; 881 cmd[1] = "-c"; 882 cmd[2] = "LC_ALL=C " + command; 883 } 884 885 results = AccessController.doPrivileged( 886 new PrivilegedExceptionAction<ArrayList<String>>() { 887 public ArrayList<String> run() throws IOException { 888 889 Process proc; 890 BufferedReader bufferedReader = null; 891 File f = Files.createTempFile("prn","xc").toFile(); 892 cmd[2] = cmd[2]+">"+f.getAbsolutePath(); 893 894 proc = Runtime.getRuntime().exec(cmd); 895 try { 896 boolean done = false; // in case of interrupt. 897 while (!done) { 898 try { 899 proc.waitFor(); 900 done = true; 901 } catch (InterruptedException e) { 902 } 903 } 904 905 if (proc.exitValue() == 0) { 906 FileReader reader = new FileReader(f); 907 bufferedReader = new BufferedReader(reader); 908 String line; 909 ArrayList<String> results = new ArrayList<>(); 910 while ((line = bufferedReader.readLine()) 911 != null) { 912 results.add(line); 913 } 914 return results; 915 } 916 } finally { 917 f.delete(); 918 // promptly close all streams. 919 if (bufferedReader != null) { 920 bufferedReader.close(); 921 } 922 proc.getInputStream().close(); 923 proc.getErrorStream().close(); 924 proc.getOutputStream().close(); 925 } 926 return null; 927 } 928 }); 929 } catch (PrivilegedActionException e) { 930 } 931 if (results == null) { 932 return new String[0]; 933 } else { 934 return results.toArray(new String[results.size()]); 935 } 936 } 937 938 private class PrinterChangeListener implements Runnable { 939 940 @Override 941 public void run() { 942 int refreshSecs; 943 while (true) { 944 try { 945 refreshServices(); 946 } catch (Exception se) { 947 IPPPrintService.debug_println(debugPrefix+"Exception in refresh thread."); 948 break; 949 } 950 951 if ((printServices != null) && 952 (printServices.length > minRefreshTime)) { 953 // compute new refresh time 1 printer = 1 sec 954 refreshSecs = printServices.length; 955 } else { 956 refreshSecs = minRefreshTime; 957 } 958 try { 959 Thread.sleep(refreshSecs * 1000); 960 } catch (InterruptedException e) { 961 break; 962 } 963 } 964 } 965 } 966 }