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