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         getDefaultPrintService();




 277         if (CUPSPrinter.isCupsRunning()) {

 278             printerURIs = CUPSPrinter.getAllPrinters();










 279             if ((printerURIs != null) && (printerURIs.length > 0)) {
 280                 printers = new String[printerURIs.length];
 281                 for (int i=0; i<printerURIs.length; i++) {
 282                     int lastIndex = printerURIs[i].lastIndexOf("/");
 283                     printers[i] = printerURIs[i].substring(lastIndex+1);
 284                 }
 285             }
 286         } else {
 287             if (isMac() || isSysV()) {
 288                 printers = getAllPrinterNamesSysV();
 289             } else if (isAIX()) {
 290                 printers = getAllPrinterNamesAIX();
 291             } else { //BSD
 292                 printers = getAllPrinterNamesBSD();
 293             }
 294         }
 295 
 296         if (printers == null) {
 297             if (defaultPrintService != null) {
 298                 printServices = new PrintService[1];
 299                 printServices[0] = defaultPrintService;
 300             } else {
 301                 printServices = null;
 302             }
 303             return;
 304         }
 305 
 306         ArrayList printerList = new ArrayList();
 307         int defaultIndex = -1;
 308         for (int p=0; p<printers.length; p++) {
 309             if (printers[p] == null) {
 310                 continue;
 311             }
 312             if ((defaultPrintService != null)
 313                 && printers[p].equals(getPrinterDestName(defaultPrintService))) {
 314                 defaultIndex = addPrintServiceToList(printerList, defaultPrintService);
 315             } else {
 316                 if (printServices == null) {
 317                     IPPPrintService.debug_println(debugPrefix+
 318                                                   "total# of printers = "+printers.length);
 319 
 320                     if (CUPSPrinter.isCupsRunning()) {
 321                         try {
 322                             addPrintServiceToList(printerList,
 323                                                   new IPPPrintService(printers[p],
 324                                                                    printerURIs[p],
 325                                                                    true));
 326                         } catch (Exception e) {
 327                             IPPPrintService.debug_println(debugPrefix+
 328                                                           " getAllPrinters Exception "+
 329                                                           e);
 330 
 331                         }
 332                     } else {
 333                         printerList.add(new UnixPrintService(printers[p]));
 334                     }
 335                 } else {
 336                     int j;
 337                     for (j=0; j<printServices.length; j++) {
 338                         if (printServices[j] != null) {
 339                             if (printers[p].equals(getPrinterDestName(printServices[j]))) {
 340                                 printerList.add(printServices[j]);
 341                                 printServices[j] = null;
 342                                 break;
 343                             }
 344                         }
 345                     }
 346 
 347                     if (j == printServices.length) {      // not found?
 348                         if (CUPSPrinter.isCupsRunning()) {
 349                             try {
 350                                 addPrintServiceToList(printerList,
 351                                              new IPPPrintService(printers[p],
 352                                                                  printerURIs[p],
 353                                                                  true));
 354                             } catch (Exception e) {
 355                                 IPPPrintService.debug_println(debugPrefix+
 356                                                               " getAllPrinters Exception "+
 357                                                               e);
 358 
 359                             }
 360                         } else {
 361                             printerList.add(new UnixPrintService(printers[p]));
 362                         }
 363                     }
 364                 }
 365             }
 366         }
 367 
 368         // Look for deleted services and invalidate these
 369         if (printServices != null) {
 370             for (int j=0; j < printServices.length; j++) {
 371                 if ((printServices[j] instanceof UnixPrintService) &&
 372                     (!printServices[j].equals(defaultPrintService))) {
 373                     ((UnixPrintService)printServices[j]).invalidateService();
 374                 }
 375             }
 376         }
 377 
 378         //if defaultService is not found in printerList
 379         if (defaultIndex == -1 && defaultPrintService != null) {
 380             defaultIndex = addPrintServiceToList(printerList, defaultPrintService);
 381         }
 382 
 383         printServices = (PrintService[])printerList.toArray(
 384                                       new PrintService[] {});
 385 
 386         // swap default with the first in the list
 387         if (defaultIndex > 0) {
 388             PrintService saveService = printServices[0];
 389             printServices[0] = printServices[defaultIndex];
 390             printServices[defaultIndex] = saveService;
 391         }
 392     }
 393 
 394     private boolean matchesAttributes(PrintService service,
 395                                       PrintServiceAttributeSet attributes) {
 396 
 397         Attribute [] attrs =  attributes.toArray();
 398         Attribute serviceAttr;
 399         for (int i=0; i<attrs.length; i++) {
 400             serviceAttr
 401                 = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory());
 402             if (serviceAttr == null || !serviceAttr.equals(attrs[i])) {
 403                 return false;
 404             }
 405         }
 406         return true;
 407     }
 408 
 409       /* This checks for validity of the printer name before passing as
 410        * parameter to a shell command.
 411        */
 412       private boolean checkPrinterName(String s) {
 413         char c;
 414 
 415         for (int i=0; i < s.length(); i++) {
 416           c = s.charAt(i);
 417           if (Character.isLetterOrDigit(c) ||
 418               c == '-' || c == '_' || c == '.' || c == '/') {
 419             continue;
 420           } else {
 421             return false;
 422           }
 423         }
 424         return true;
 425       }
 426 
 427     /*
 428      * Gets the printer name compatible with the list of printers returned by
 429      * the system when we query default or all the available printers.
 430      */
 431     private String getPrinterDestName(PrintService ps) {
 432         if (isMac()) {
 433             return ((IPPPrintService)ps).getDest();
 434         }
 435         return ps.getName();
 436     }
 437 
 438     /* On a network with many (hundreds) of network printers, it
 439      * can save several seconds if you know all you want is a particular
 440      * printer, to ask for that printer rather than retrieving all printers.
 441      */
 442     private PrintService getServiceByName(PrinterName nameAttr) {
 443         String name = nameAttr.getValue();
 444         if (name == null || name.equals("") || !checkPrinterName(name)) {
 445             return null;
 446         }
 447         /* check if all printers are already available */
 448         if (printServices != null) {
 449             for (PrintService printService : printServices) {
 450                 PrinterName printerName = printService.getAttribute(PrinterName.class);
 451                 if (printerName.getValue().equals(name)) {
 452                     return printService;
 453                 }
 454             }
 455         }
 456         /* take CUPS into account first */
 457         if (CUPSPrinter.isCupsRunning()) {
 458             try {
 459                 return new IPPPrintService(name,
 460                                            new URL("http://"+
 461                                                    CUPSPrinter.getServer()+":"+
 462                                                    CUPSPrinter.getPort()+"/"+
 463                                                    name));
 464             } catch (Exception e) {
 465                 IPPPrintService.debug_println(debugPrefix+
 466                                               " getServiceByName Exception "+
 467                                               e);
 468             }
 469         }
 470         /* fallback if nothing not having a printer at this point */
 471         PrintService printer = null;
 472         if (isMac() || isSysV()) {
 473             printer = getNamedPrinterNameSysV(name);
 474         } else if (isAIX()) {
 475             printer = getNamedPrinterNameAIX(name);
 476         } else {
 477             printer = getNamedPrinterNameBSD(name);
 478         }
 479         return printer;
 480     }
 481 
 482     private PrintService[]
 483         getPrintServices(PrintServiceAttributeSet serviceSet) {
 484 
 485         if (serviceSet == null || serviceSet.isEmpty()) {
 486             return getPrintServices();
 487         }
 488 
 489         /* Typically expect that if a service attribute is specified that
 490          * its a printer name and there ought to be only one match.
 491          * Directly retrieve that service and confirm
 492          * that it meets the other requirements.
 493          * If printer name isn't mentioned then go a slow path checking
 494          * all printers if they meet the reqiremements.
 495          */
 496         PrintService[] services;
 497         PrinterName name = (PrinterName)serviceSet.get(PrinterName.class);
 498         PrintService defService;
 499         if (name != null && (defService = getDefaultPrintService()) != null) {
 500             /* To avoid execing a unix command  see if the client is asking
 501              * for the default printer by name, since we already have that
 502              * initialised.
 503              */
 504 
 505             PrinterName defName = defService.getAttribute(PrinterName.class);
 506 
 507             if (defName != null && name.equals(defName)) {
 508                 if (matchesAttributes(defService, serviceSet)) {
 509                     services = new PrintService[1];
 510                     services[0] = defService;
 511                     return services;
 512                 } else {
 513                     return new PrintService[0];
 514                 }
 515             } else {
 516                 /* Its not the default service */
 517                 PrintService service = getServiceByName(name);
 518                 if (service != null &&
 519                     matchesAttributes(service, serviceSet)) {
 520                     services = new PrintService[1];
 521                     services[0] = service;
 522                     return services;
 523                 } else {
 524                     return new PrintService[0];
 525                 }
 526             }
 527         } else {
 528             /* specified service attributes don't include a name.*/
 529             Vector matchedServices = new Vector();
 530             services = getPrintServices();
 531             for (int i = 0; i< services.length; i++) {
 532                 if (matchesAttributes(services[i], serviceSet)) {
 533                     matchedServices.add(services[i]);
 534                 }
 535             }
 536             services = new PrintService[matchedServices.size()];
 537             for (int i = 0; i< services.length; i++) {
 538                 services[i] = (PrintService)matchedServices.elementAt(i);
 539             }
 540             return services;
 541         }
 542     }
 543 
 544     /*
 545      * If service attributes are specified then there must be additional
 546      * filtering.
 547      */
 548     public PrintService[] getPrintServices(DocFlavor flavor,
 549                                            AttributeSet attributes) {
 550         SecurityManager security = System.getSecurityManager();
 551         if (security != null) {
 552           security.checkPrintJobAccess();
 553         }
 554         PrintRequestAttributeSet requestSet = null;
 555         PrintServiceAttributeSet serviceSet = null;
 556 
 557         if (attributes != null && !attributes.isEmpty()) {
 558 
 559             requestSet = new HashPrintRequestAttributeSet();
 560             serviceSet = new HashPrintServiceAttributeSet();
 561 
 562             Attribute[] attrs = attributes.toArray();
 563             for (int i=0; i<attrs.length; i++) {
 564                 if (attrs[i] instanceof PrintRequestAttribute) {
 565                     requestSet.add(attrs[i]);
 566                 } else if (attrs[i] instanceof PrintServiceAttribute) {
 567                     serviceSet.add(attrs[i]);
 568                 }
 569             }
 570         }
 571 
 572         PrintService[] services = getPrintServices(serviceSet);
 573         if (services.length == 0) {
 574             return services;
 575         }
 576 
 577         if (CUPSPrinter.isCupsRunning()) {
 578             ArrayList matchingServices = new ArrayList();
 579             for (int i=0; i<services.length; i++) {
 580                 try {
 581                     if (services[i].
 582                         getUnsupportedAttributes(flavor, requestSet) == null) {
 583                         matchingServices.add(services[i]);
 584                     }
 585                 } catch (IllegalArgumentException e) {
 586                 }
 587             }
 588             services = new PrintService[matchingServices.size()];
 589             return (PrintService[])matchingServices.toArray(services);
 590 
 591         } else {
 592             // We only need to compare 1 PrintService because all
 593             // UnixPrintServices are the same anyway.  We will not use
 594             // default PrintService because it might be null.
 595             PrintService service = services[0];
 596             if ((flavor == null ||
 597                  service.isDocFlavorSupported(flavor)) &&
 598                  service.getUnsupportedAttributes(flavor, requestSet) == null)
 599             {
 600                 return services;
 601             } else {
 602                 return new PrintService[0];
 603             }
 604         }
 605     }
 606 
 607     /*
 608      * return empty array as don't support multi docs
 609      */
 610     public MultiDocPrintService[]
 611         getMultiDocPrintServices(DocFlavor[] flavors,
 612                                  AttributeSet attributes) {
 613         SecurityManager security = System.getSecurityManager();
 614         if (security != null) {
 615           security.checkPrintJobAccess();
 616         }
 617         return new MultiDocPrintService[0];
 618     }
 619 
 620 
 621     public synchronized PrintService getDefaultPrintService() {
 622         SecurityManager security = System.getSecurityManager();
 623         if (security != null) {
 624           security.checkPrintJobAccess();
 625         }
 626 
 627         // clear defaultPrintService
 628         defaultPrintService = null;
 629         String psuri = null;
 630 
 631         IPPPrintService.debug_println("isRunning ? "+
 632                                       (CUPSPrinter.isCupsRunning()));
 633         if (CUPSPrinter.isCupsRunning()) {
 634             String[] printerInfo = CUPSPrinter.getDefaultPrinter();

 635             defaultPrinter = printerInfo[0];
 636             psuri = printerInfo[1];

 637         } else {
 638             if (isMac() || isSysV()) {
 639                 defaultPrinter = getDefaultPrinterNameSysV();
 640             } else if (isAIX()) {
 641                 defaultPrinter = getDefaultPrinterNameAIX();
 642             } else {
 643                 defaultPrinter = getDefaultPrinterNameBSD();
 644             }
 645         }
 646         if (defaultPrinter == null) {
 647             return null;
 648         }
 649         defaultPrintService = null;
 650         if (printServices != null) {
 651             for (int j=0; j<printServices.length; j++) {
 652                 if (defaultPrinter.equals(getPrinterDestName(printServices[j]))) {
 653                     defaultPrintService = printServices[j];
 654                     break;
 655                 }
 656             }
 657         }
 658         if (defaultPrintService == null) {
 659             if (CUPSPrinter.isCupsRunning()) {
 660                 try {
 661                     PrintService defaultPS;
 662                     if ((psuri != null) && !psuri.startsWith("file")) {
 663                         defaultPS = new IPPPrintService(defaultPrinter,
 664                                                         psuri, true);
 665                     } else {
 666                         defaultPS = new IPPPrintService(defaultPrinter,
 667                                             new URL("http://"+
 668                                                     CUPSPrinter.getServer()+":"+
 669                                                     CUPSPrinter.getPort()+"/"+
 670                                                     defaultPrinter));
 671                     }
 672                     defaultPrintService = defaultPS;
 673                 } catch (Exception e) {
 674                 }
 675             } else {
 676                 defaultPrintService = new UnixPrintService(defaultPrinter);
 677             }
 678         }
 679 
 680         return defaultPrintService;
 681     }
 682 
 683     public synchronized void
 684         getServicesInbackground(BackgroundLookupListener listener) {
 685         if (printServices != null) {
 686             listener.notifyServices(printServices);
 687         } else {
 688             if (lookupListeners == null) {
 689                 lookupListeners = new Vector();
 690                 lookupListeners.add(listener);
 691                 Thread lookupThread = new Thread(this);
 692                 lookupThread.start();
 693             } else {
 694                 lookupListeners.add(listener);
 695             }
 696         }
 697     }
 698 
 699     /* This method isn't used in most cases because we rely on code in
 700      * javax.print.PrintServiceLookup. This is needed just for the cases
 701      * where those interfaces are by-passed.
 702      */
 703     private PrintService[] copyOf(PrintService[] inArr) {
 704         if (inArr == null || inArr.length == 0) {
 705             return inArr;
 706         } else {
 707             PrintService []outArr = new PrintService[inArr.length];
 708             System.arraycopy(inArr, 0, outArr, 0, inArr.length);
 709             return outArr;
 710         }
 711     }
 712 
 713     public void run() {
 714         PrintService[] services = getPrintServices();
 715         synchronized (this) {
 716             BackgroundLookupListener listener;
 717             for (int i=0; i<lookupListeners.size(); i++) {
 718                 listener =
 719                     (BackgroundLookupListener)lookupListeners.elementAt(i);
 720                 listener.notifyServices(copyOf(services));
 721             }
 722             lookupListeners = null;
 723         }
 724     }
 725 
 726     private String getDefaultPrinterNameBSD() {
 727         if (cmdIndex == UNINITIALIZED) {
 728             cmdIndex = getBSDCommandIndex();
 729         }
 730         String[] names = execCmd(lpcFirstCom[cmdIndex]);
 731         if (names == null || names.length == 0) {
 732             return null;
 733         }
 734 
 735         if ((cmdIndex==BSD_LPD_NG) &&
 736             (names[0].startsWith("missingprinter"))) {
 737             return null;
 738         }
 739         return names[0];
 740     }
 741 
 742     private PrintService getNamedPrinterNameBSD(String name) {
 743       if (cmdIndex == UNINITIALIZED) {
 744         cmdIndex = getBSDCommandIndex();
 745       }
 746       String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex];
 747       String[] result = execCmd(command);
 748 
 749       if (result == null || !(result[0].equals(name))) {
 750           return null;
 751       }
 752       return new UnixPrintService(name);
 753     }
 754 
 755     private String[] getAllPrinterNamesBSD() {
 756         if (cmdIndex == UNINITIALIZED) {
 757             cmdIndex = getBSDCommandIndex();
 758         }
 759         String[] names = execCmd(lpcAllCom[cmdIndex]);
 760         if (names == null || names.length == 0) {
 761           return null;
 762         }
 763         return names;
 764     }
 765 
 766     static String getDefaultPrinterNameSysV() {
 767         String defaultPrinter = "lp";
 768         String command = "/usr/bin/lpstat -d";
 769 
 770         String [] names = execCmd(command);
 771         if (names == null || names.length == 0) {
 772             return defaultPrinter;
 773         } else {
 774             int index = names[0].indexOf(":");
 775             if (index == -1  || (names[0].length() <= index+1)) {
 776                 return null;
 777             } else {
 778                 String name = names[0].substring(index+1).trim();
 779                 if (name.length() == 0) {
 780                     return null;
 781                 } else {
 782                     return name;
 783                 }
 784             }
 785         }
 786     }
 787 
 788     private PrintService getNamedPrinterNameSysV(String name) {
 789 
 790         String command = "/usr/bin/lpstat -v " + name;
 791         String []result = execCmd(command);
 792 
 793         if (result == null || result[0].indexOf("unknown printer") > 0) {
 794             return null;
 795         } else {
 796             return new UnixPrintService(name);
 797         }
 798     }
 799 
 800     private String[] getAllPrinterNamesSysV() {
 801         String defaultPrinter = "lp";
 802         String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort";
 803 
 804         String [] names = execCmd(command);
 805         ArrayList printerNames = new ArrayList();
 806         for (int i=0; i < names.length; i++) {
 807             if (!names[i].equals("_default") &&
 808                 !names[i].equals(defaultPrinter) &&
 809                 !names[i].equals("")) {
 810                 printerNames.add(names[i]);
 811             }
 812         }
 813         return (String[])printerNames.toArray(new String[printerNames.size()]);
 814     }
 815 
 816     private String getDefaultPrinterNameAIX() {
 817         String[] names = execCmd(lpNameComAix[aix_lpstat_d]);
 818         // Remove headers and bogus entries added by remote printers.
 819         names = UnixPrintService.filterPrinterNamesAIX(names);
 820         if (names == null || names.length != 1) {
 821             // No default printer found
 822             return null;
 823         } else {
 824             return names[0];
 825         }
 826     }
 827 
 828     private PrintService getNamedPrinterNameAIX(String name) {
 829         // On AIX there should be no blank after '-v'.
 830         String[] result = execCmd(lpNameComAix[aix_lpstat_v] + name);
 831         // Remove headers and bogus entries added by remote printers.
 832         result = UnixPrintService.filterPrinterNamesAIX(result);
 833         if (result == null || result.length != 1) {
 834             return null;
 835         } else {
 836             return new UnixPrintService(name);
 837         }
 838     }
 839 
 840     private String[] getAllPrinterNamesAIX() {
 841         // Determine all printers of the system.
 842         String [] names = execCmd(lpNameComAix[aix_defaultPrinterEnumeration]);
 843 
 844         // Remove headers and bogus entries added by remote printers.
 845         names = UnixPrintService.filterPrinterNamesAIX(names);
 846 
 847         ArrayList<String> printerNames = new ArrayList<String>();
 848         for ( int i=0; i < names.length; i++) {
 849             printerNames.add(names[i]);
 850         }
 851         return printerNames.toArray(new String[printerNames.size()]);
 852     }
 853 
 854     static String[] execCmd(final String command) {
 855         ArrayList results = null;
 856         try {
 857             final String[] cmd = new String[3];
 858             if (isSysV() || isAIX()) {
 859                 cmd[0] = "/usr/bin/sh";
 860                 cmd[1] = "-c";
 861                 cmd[2] = "env LC_ALL=C " + command;
 862             } else {
 863                 cmd[0] = "/bin/sh";
 864                 cmd[1] = "-c";
 865                 cmd[2] = "LC_ALL=C " + command;
 866             }
 867 
 868             results = (ArrayList)AccessController.doPrivileged(
 869                 new PrivilegedExceptionAction() {
 870                     public Object run() throws IOException {
 871 
 872                         Process proc;
 873                         BufferedReader bufferedReader = null;
 874                         File f = Files.createTempFile("prn","xc").toFile();
 875                         cmd[2] = cmd[2]+">"+f.getAbsolutePath();
 876 
 877                         proc = Runtime.getRuntime().exec(cmd);
 878                         try {
 879                             boolean done = false; // in case of interrupt.
 880                             while (!done) {
 881                                 try {
 882                                     proc.waitFor();
 883                                     done = true;
 884                                 } catch (InterruptedException e) {
 885                                 }
 886                             }
 887 
 888                             if (proc.exitValue() == 0) {
 889                                 FileReader reader = new FileReader(f);
 890                                 bufferedReader = new BufferedReader(reader);
 891                                 String line;
 892                                 ArrayList results = new ArrayList();
 893                                 while ((line = bufferedReader.readLine())
 894                                        != null) {
 895                                     results.add(line);
 896                                 }
 897                                 return results;
 898                             }
 899                         } finally {
 900                             f.delete();
 901                             // promptly close all streams.
 902                             if (bufferedReader != null) {
 903                                 bufferedReader.close();
 904                             }
 905                             proc.getInputStream().close();
 906                             proc.getErrorStream().close();
 907                             proc.getOutputStream().close();
 908                         }
 909                         return null;
 910                     }
 911                 });
 912         } catch (PrivilegedActionException e) {
 913         }
 914         if (results == null) {
 915             return new String[0];
 916         } else {
 917             return (String[])results.toArray(new String[results.size()]);
 918         }
 919     }
 920 
 921     private class PrinterChangeListener extends Thread {
 922 
 923         public void run() {
 924             int refreshSecs;
 925             while (true) {
 926                 try {
 927                     refreshServices();
 928                 } catch (Exception se) {
 929                     IPPPrintService.debug_println(debugPrefix+"Exception in refresh thread.");
 930                     break;
 931                 }
 932 
 933                 if ((printServices != null) &&
 934                     (printServices.length > minRefreshTime)) {
 935                     // compute new refresh time 1 printer = 1 sec
 936                     refreshSecs = printServices.length;
 937                 } else {
 938                     refreshSecs = minRefreshTime;
 939                 }
 940                 try {
 941                     sleep(refreshSecs * 1000);
 942                 } catch (InterruptedException e) {
 943                     break;
 944                 }
 945             }
 946         }
 947     }
 948 }
--- EOF ---