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