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