1 /* 2 * Copyright (c) 2000, 2014, 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 UnixPrintServiceLookup 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 lookupListeners = null; 73 private static String debugPrefix = "UnixPrintServiceLookup>> "; 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 = (new Integer(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 UnixPrintServiceLookup() { 212 // start the printer listener thread 213 if (pollServices) { 214 PrinterChangeListener thr = new PrinterChangeListener(); 215 thr.setDaemon(true); 216 thr.start(); 217 IPPPrintService.debug_println(debugPrefix+"polling turned on"); 218 } 219 } 220 221 /* Want the PrintService which is default print service to have 222 * equality of reference with the equivalent in list of print services 223 * This isn't required by the API and there's a risk doing this will 224 * lead people to assume its guaranteed. 225 */ 226 public synchronized PrintService[] getPrintServices() { 227 SecurityManager security = System.getSecurityManager(); 228 if (security != null) { 229 security.checkPrintJobAccess(); 230 } 231 232 if (printServices == null || !pollServices) { 233 refreshServices(); 234 } 235 if (printServices == null) { 236 return new PrintService[0]; 237 } else { 238 return printServices.clone(); 239 } 240 } 241 242 private int addPrintServiceToList(ArrayList printerList, PrintService ps) { 243 int index = printerList.indexOf(ps); 244 // Check if PrintService with same name is already in the list. 245 if (CUPSPrinter.isCupsRunning() && index != -1) { 246 // Bug in Linux: Duplicate entry of a remote printer 247 // and treats it as local printer but it is returning wrong 248 // information when queried using IPP. Workaround is to remove it. 249 // Even CUPS ignores these entries as shown in lpstat or using 250 // their web configuration. 251 PrinterURI uri = ps.getAttribute(PrinterURI.class); 252 if (uri.getURI().getHost().equals("localhost")) { 253 IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, ignoring the new local printer: "+ps); 254 return index; // Do not add this. 255 } 256 PrintService oldPS = (PrintService)(printerList.get(index)); 257 uri = oldPS.getAttribute(PrinterURI.class); 258 if (uri.getURI().getHost().equals("localhost")) { 259 IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, removing existing local printer: "+oldPS); 260 printerList.remove(oldPS); 261 } else { 262 return index; 263 } 264 } 265 printerList.add(ps); 266 return (printerList.size() - 1); 267 } 268 269 270 // refreshes "printServices" 271 public synchronized void refreshServices() { 272 /* excludes the default printer */ 273 String[] printers = null; // array of printer names 274 String[] printerURIs = null; //array of printer URIs 275 276 try { 277 getDefaultPrintService(); 278 } catch (Throwable t) { 279 IPPPrintService.debug_println(debugPrefix+ 280 "Exception getting default printer : " + t); 281 } 282 if (CUPSPrinter.isCupsRunning()) { 283 try { 284 printerURIs = CUPSPrinter.getAllPrinters(); 285 IPPPrintService.debug_println("CUPS URIs = " + printerURIs); 286 if (printerURIs != null) { 287 for (int p = 0; p < printerURIs.length; p++) { 288 IPPPrintService.debug_println("URI="+printerURIs[p]); 289 } 290 } 291 } catch (Throwable t) { 292 IPPPrintService.debug_println(debugPrefix+ 293 "Exception getting all CUPS printers : " + t); 294 } 295 if ((printerURIs != null) && (printerURIs.length > 0)) { 296 printers = new String[printerURIs.length]; 297 for (int i=0; i<printerURIs.length; i++) { 298 int lastIndex = printerURIs[i].lastIndexOf("/"); 299 printers[i] = printerURIs[i].substring(lastIndex+1); 300 } 301 } 302 } else { 303 if (isMac() || isSysV()) { 304 printers = getAllPrinterNamesSysV(); 305 } else if (isAIX()) { 306 printers = getAllPrinterNamesAIX(); 307 } else { //BSD 308 printers = getAllPrinterNamesBSD(); 309 } 310 } 311 312 if (printers == null) { 313 if (defaultPrintService != null) { 314 printServices = new PrintService[1]; 315 printServices[0] = defaultPrintService; 316 } else { 317 printServices = null; 318 } 319 return; 320 } 321 322 ArrayList printerList = new ArrayList(); 323 int defaultIndex = -1; 324 for (int p=0; p<printers.length; p++) { 325 if (printers[p] == null) { 326 continue; 327 } 328 if ((defaultPrintService != null) 329 && printers[p].equals(getPrinterDestName(defaultPrintService))) { 330 defaultIndex = addPrintServiceToList(printerList, defaultPrintService); 331 } else { 332 if (printServices == null) { 333 IPPPrintService.debug_println(debugPrefix+ 334 "total# of printers = "+printers.length); 335 336 if (CUPSPrinter.isCupsRunning()) { 337 try { 338 addPrintServiceToList(printerList, 339 new IPPPrintService(printers[p], 340 printerURIs[p], 341 true)); 342 } catch (Exception e) { 343 IPPPrintService.debug_println(debugPrefix+ 344 " getAllPrinters Exception "+ 345 e); 346 347 } 348 } else { 349 printerList.add(new UnixPrintService(printers[p])); 350 } 351 } else { 352 int j; 353 for (j=0; j<printServices.length; j++) { 354 if (printServices[j] != null) { 355 if (printers[p].equals(getPrinterDestName(printServices[j]))) { 356 printerList.add(printServices[j]); 357 printServices[j] = null; 358 break; 359 } 360 } 361 } 362 363 if (j == printServices.length) { // not found? 364 if (CUPSPrinter.isCupsRunning()) { 365 try { 366 addPrintServiceToList(printerList, 367 new IPPPrintService(printers[p], 368 printerURIs[p], 369 true)); 370 } catch (Exception e) { 371 IPPPrintService.debug_println(debugPrefix+ 372 " getAllPrinters Exception "+ 373 e); 374 375 } 376 } else { 377 printerList.add(new UnixPrintService(printers[p])); 378 } 379 } 380 } 381 } 382 } 383 384 // Look for deleted services and invalidate these 385 if (printServices != null) { 386 for (int j=0; j < printServices.length; j++) { 387 if ((printServices[j] instanceof UnixPrintService) && 388 (!printServices[j].equals(defaultPrintService))) { 389 ((UnixPrintService)printServices[j]).invalidateService(); 390 } 391 } 392 } 393 394 //if defaultService is not found in printerList 395 if (defaultIndex == -1 && defaultPrintService != null) { 396 defaultIndex = addPrintServiceToList(printerList, defaultPrintService); 397 } 398 399 printServices = (PrintService[])printerList.toArray( 400 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 Attribute serviceAttr; 415 for (int i=0; i<attrs.length; i++) { 416 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.equals("") || !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 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] = (PrintService)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 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 (PrintService[])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 = 737 (BackgroundLookupListener)lookupListeners.elementAt(i); 738 listener.notifyServices(copyOf(services)); 739 } 740 lookupListeners = null; 741 } 742 } 743 744 private String getDefaultPrinterNameBSD() { 745 if (cmdIndex == UNINITIALIZED) { 746 cmdIndex = getBSDCommandIndex(); 747 } 748 String[] names = execCmd(lpcFirstCom[cmdIndex]); 749 if (names == null || names.length == 0) { 750 return null; 751 } 752 753 if ((cmdIndex==BSD_LPD_NG) && 754 (names[0].startsWith("missingprinter"))) { 755 return null; 756 } 757 return names[0]; 758 } 759 760 private PrintService getNamedPrinterNameBSD(String name) { 761 if (cmdIndex == UNINITIALIZED) { 762 cmdIndex = getBSDCommandIndex(); 763 } 764 String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex]; 765 String[] result = execCmd(command); 766 767 if (result == null || !(result[0].equals(name))) { 768 return null; 769 } 770 return new UnixPrintService(name); 771 } 772 773 private String[] getAllPrinterNamesBSD() { 774 if (cmdIndex == UNINITIALIZED) { 775 cmdIndex = getBSDCommandIndex(); 776 } 777 String[] names = execCmd(lpcAllCom[cmdIndex]); 778 if (names == null || names.length == 0) { 779 return null; 780 } 781 return names; 782 } 783 784 static String getDefaultPrinterNameSysV() { 785 String defaultPrinter = "lp"; 786 String command = "/usr/bin/lpstat -d"; 787 788 String [] names = execCmd(command); 789 if (names == null || names.length == 0) { 790 return defaultPrinter; 791 } else { 792 int index = names[0].indexOf(":"); 793 if (index == -1 || (names[0].length() <= index+1)) { 794 return null; 795 } else { 796 String name = names[0].substring(index+1).trim(); 797 if (name.length() == 0) { 798 return null; 799 } else { 800 return name; 801 } 802 } 803 } 804 } 805 806 private PrintService getNamedPrinterNameSysV(String name) { 807 808 String command = "/usr/bin/lpstat -v " + name; 809 String []result = execCmd(command); 810 811 if (result == null || result[0].indexOf("unknown printer") > 0) { 812 return null; 813 } else { 814 return new UnixPrintService(name); 815 } 816 } 817 818 private String[] getAllPrinterNamesSysV() { 819 String defaultPrinter = "lp"; 820 String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort"; 821 822 String [] names = execCmd(command); 823 ArrayList printerNames = new ArrayList(); 824 for (int i=0; i < names.length; i++) { 825 if (!names[i].equals("_default") && 826 !names[i].equals(defaultPrinter) && 827 !names[i].equals("")) { 828 printerNames.add(names[i]); 829 } 830 } 831 return (String[])printerNames.toArray(new String[printerNames.size()]); 832 } 833 834 private String getDefaultPrinterNameAIX() { 835 String[] names = execCmd(lpNameComAix[aix_lpstat_d]); 836 // Remove headers and bogus entries added by remote printers. 837 names = UnixPrintService.filterPrinterNamesAIX(names); 838 if (names == null || names.length != 1) { 839 // No default printer found 840 return null; 841 } else { 842 return names[0]; 843 } 844 } 845 846 private PrintService getNamedPrinterNameAIX(String name) { 847 // On AIX there should be no blank after '-v'. 848 String[] result = execCmd(lpNameComAix[aix_lpstat_v] + name); 849 // Remove headers and bogus entries added by remote printers. 850 result = UnixPrintService.filterPrinterNamesAIX(result); 851 if (result == null || result.length != 1) { 852 return null; 853 } else { 854 return new UnixPrintService(name); 855 } 856 } 857 858 private String[] getAllPrinterNamesAIX() { 859 // Determine all printers of the system. 860 String [] names = execCmd(lpNameComAix[aix_defaultPrinterEnumeration]); 861 862 // Remove headers and bogus entries added by remote printers. 863 names = UnixPrintService.filterPrinterNamesAIX(names); 864 865 ArrayList<String> printerNames = new ArrayList<String>(); 866 for ( int i=0; i < names.length; i++) { 867 printerNames.add(names[i]); 868 } 869 return printerNames.toArray(new String[printerNames.size()]); 870 } 871 872 static String[] execCmd(final String command) { 873 ArrayList results = null; 874 try { 875 final String[] cmd = new String[3]; 876 if (isSysV() || isAIX()) { 877 cmd[0] = "/usr/bin/sh"; 878 cmd[1] = "-c"; 879 cmd[2] = "env LC_ALL=C " + command; 880 } else { 881 cmd[0] = "/bin/sh"; 882 cmd[1] = "-c"; 883 cmd[2] = "LC_ALL=C " + command; 884 } 885 886 results = (ArrayList)AccessController.doPrivileged( 887 new PrivilegedExceptionAction() { 888 public Object run() throws IOException { 889 890 Process proc; 891 BufferedReader bufferedReader = null; 892 File f = Files.createTempFile("prn","xc").toFile(); 893 cmd[2] = cmd[2]+">"+f.getAbsolutePath(); 894 895 proc = Runtime.getRuntime().exec(cmd); 896 try { 897 boolean done = false; // in case of interrupt. 898 while (!done) { 899 try { 900 proc.waitFor(); 901 done = true; 902 } catch (InterruptedException e) { 903 } 904 } 905 906 if (proc.exitValue() == 0) { 907 FileReader reader = new FileReader(f); 908 bufferedReader = new BufferedReader(reader); 909 String line; 910 ArrayList results = new ArrayList(); 911 while ((line = bufferedReader.readLine()) 912 != null) { 913 results.add(line); 914 } 915 return results; 916 } 917 } finally { 918 f.delete(); 919 // promptly close all streams. 920 if (bufferedReader != null) { 921 bufferedReader.close(); 922 } 923 proc.getInputStream().close(); 924 proc.getErrorStream().close(); 925 proc.getOutputStream().close(); 926 } 927 return null; 928 } 929 }); 930 } catch (PrivilegedActionException e) { 931 } 932 if (results == null) { 933 return new String[0]; 934 } else { 935 return (String[])results.toArray(new String[results.size()]); 936 } 937 } 938 939 private class PrinterChangeListener extends Thread { 940 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 sleep(refreshSecs * 1000); 960 } catch (InterruptedException e) { 961 break; 962 } 963 } 964 } 965 } 966 }