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