jdk/src/java.desktop/unix/classes/sun/print/UnixPrintServiceLookup.java
changeset 27324 f54441c74373
parent 27323 babdaa819add
parent 27315 00f085d0f75c
child 27325 948cceef81ba
equal deleted inserted replaced
27323:babdaa819add 27324:f54441c74373
     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<BackgroundLookupListener> 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<PrintService> 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 = 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<PrintService> 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 = printerList.toArray(new PrintService[] {});
       
   400 
       
   401         // swap default with the first in the list
       
   402         if (defaultIndex > 0) {
       
   403             PrintService saveService = printServices[0];
       
   404             printServices[0] = printServices[defaultIndex];
       
   405             printServices[defaultIndex] = saveService;
       
   406         }
       
   407     }
       
   408 
       
   409     private boolean matchesAttributes(PrintService service,
       
   410                                       PrintServiceAttributeSet attributes) {
       
   411 
       
   412         Attribute [] attrs =  attributes.toArray();
       
   413         for (int i=0; i<attrs.length; i++) {
       
   414             @SuppressWarnings("unchecked")
       
   415             Attribute serviceAttr
       
   416                 = service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory());
       
   417             if (serviceAttr == null || !serviceAttr.equals(attrs[i])) {
       
   418                 return false;
       
   419             }
       
   420         }
       
   421         return true;
       
   422     }
       
   423 
       
   424       /* This checks for validity of the printer name before passing as
       
   425        * parameter to a shell command.
       
   426        */
       
   427       private boolean checkPrinterName(String s) {
       
   428         char c;
       
   429 
       
   430         for (int i=0; i < s.length(); i++) {
       
   431           c = s.charAt(i);
       
   432           if (Character.isLetterOrDigit(c) ||
       
   433               c == '-' || c == '_' || c == '.' || c == '/') {
       
   434             continue;
       
   435           } else {
       
   436             return false;
       
   437           }
       
   438         }
       
   439         return true;
       
   440       }
       
   441 
       
   442     /*
       
   443      * Gets the printer name compatible with the list of printers returned by
       
   444      * the system when we query default or all the available printers.
       
   445      */
       
   446     private String getPrinterDestName(PrintService ps) {
       
   447         if (isMac()) {
       
   448             return ((IPPPrintService)ps).getDest();
       
   449         }
       
   450         return ps.getName();
       
   451     }
       
   452 
       
   453     /* On a network with many (hundreds) of network printers, it
       
   454      * can save several seconds if you know all you want is a particular
       
   455      * printer, to ask for that printer rather than retrieving all printers.
       
   456      */
       
   457     private PrintService getServiceByName(PrinterName nameAttr) {
       
   458         String name = nameAttr.getValue();
       
   459         if (name == null || name.equals("") || !checkPrinterName(name)) {
       
   460             return null;
       
   461         }
       
   462         /* check if all printers are already available */
       
   463         if (printServices != null) {
       
   464             for (PrintService printService : printServices) {
       
   465                 PrinterName printerName = printService.getAttribute(PrinterName.class);
       
   466                 if (printerName.getValue().equals(name)) {
       
   467                     return printService;
       
   468                 }
       
   469             }
       
   470         }
       
   471         /* take CUPS into account first */
       
   472         if (CUPSPrinter.isCupsRunning()) {
       
   473             try {
       
   474                 return new IPPPrintService(name,
       
   475                                            new URL("http://"+
       
   476                                                    CUPSPrinter.getServer()+":"+
       
   477                                                    CUPSPrinter.getPort()+"/"+
       
   478                                                    name));
       
   479             } catch (Exception e) {
       
   480                 IPPPrintService.debug_println(debugPrefix+
       
   481                                               " getServiceByName Exception "+
       
   482                                               e);
       
   483             }
       
   484         }
       
   485         /* fallback if nothing not having a printer at this point */
       
   486         PrintService printer = null;
       
   487         if (isMac() || isSysV()) {
       
   488             printer = getNamedPrinterNameSysV(name);
       
   489         } else if (isAIX()) {
       
   490             printer = getNamedPrinterNameAIX(name);
       
   491         } else {
       
   492             printer = getNamedPrinterNameBSD(name);
       
   493         }
       
   494         return printer;
       
   495     }
       
   496 
       
   497     private PrintService[]
       
   498         getPrintServices(PrintServiceAttributeSet serviceSet) {
       
   499 
       
   500         if (serviceSet == null || serviceSet.isEmpty()) {
       
   501             return getPrintServices();
       
   502         }
       
   503 
       
   504         /* Typically expect that if a service attribute is specified that
       
   505          * its a printer name and there ought to be only one match.
       
   506          * Directly retrieve that service and confirm
       
   507          * that it meets the other requirements.
       
   508          * If printer name isn't mentioned then go a slow path checking
       
   509          * all printers if they meet the reqiremements.
       
   510          */
       
   511         PrintService[] services;
       
   512         PrinterName name = (PrinterName)serviceSet.get(PrinterName.class);
       
   513         PrintService defService;
       
   514         if (name != null && (defService = getDefaultPrintService()) != null) {
       
   515             /* To avoid execing a unix command  see if the client is asking
       
   516              * for the default printer by name, since we already have that
       
   517              * initialised.
       
   518              */
       
   519 
       
   520             PrinterName defName = defService.getAttribute(PrinterName.class);
       
   521 
       
   522             if (defName != null && name.equals(defName)) {
       
   523                 if (matchesAttributes(defService, serviceSet)) {
       
   524                     services = new PrintService[1];
       
   525                     services[0] = defService;
       
   526                     return services;
       
   527                 } else {
       
   528                     return new PrintService[0];
       
   529                 }
       
   530             } else {
       
   531                 /* Its not the default service */
       
   532                 PrintService service = getServiceByName(name);
       
   533                 if (service != null &&
       
   534                     matchesAttributes(service, serviceSet)) {
       
   535                     services = new PrintService[1];
       
   536                     services[0] = service;
       
   537                     return services;
       
   538                 } else {
       
   539                     return new PrintService[0];
       
   540                 }
       
   541             }
       
   542         } else {
       
   543             /* specified service attributes don't include a name.*/
       
   544             Vector<PrintService> matchedServices = new Vector<>();
       
   545             services = getPrintServices();
       
   546             for (int i = 0; i< services.length; i++) {
       
   547                 if (matchesAttributes(services[i], serviceSet)) {
       
   548                     matchedServices.add(services[i]);
       
   549                 }
       
   550             }
       
   551             services = new PrintService[matchedServices.size()];
       
   552             for (int i = 0; i< services.length; i++) {
       
   553                 services[i] = matchedServices.elementAt(i);
       
   554             }
       
   555             return services;
       
   556         }
       
   557     }
       
   558 
       
   559     /*
       
   560      * If service attributes are specified then there must be additional
       
   561      * filtering.
       
   562      */
       
   563     public PrintService[] getPrintServices(DocFlavor flavor,
       
   564                                            AttributeSet attributes) {
       
   565         SecurityManager security = System.getSecurityManager();
       
   566         if (security != null) {
       
   567           security.checkPrintJobAccess();
       
   568         }
       
   569         PrintRequestAttributeSet requestSet = null;
       
   570         PrintServiceAttributeSet serviceSet = null;
       
   571 
       
   572         if (attributes != null && !attributes.isEmpty()) {
       
   573 
       
   574             requestSet = new HashPrintRequestAttributeSet();
       
   575             serviceSet = new HashPrintServiceAttributeSet();
       
   576 
       
   577             Attribute[] attrs = attributes.toArray();
       
   578             for (int i=0; i<attrs.length; i++) {
       
   579                 if (attrs[i] instanceof PrintRequestAttribute) {
       
   580                     requestSet.add(attrs[i]);
       
   581                 } else if (attrs[i] instanceof PrintServiceAttribute) {
       
   582                     serviceSet.add(attrs[i]);
       
   583                 }
       
   584             }
       
   585         }
       
   586 
       
   587         PrintService[] services = getPrintServices(serviceSet);
       
   588         if (services.length == 0) {
       
   589             return services;
       
   590         }
       
   591 
       
   592         if (CUPSPrinter.isCupsRunning()) {
       
   593             ArrayList<PrintService> matchingServices = new ArrayList<>();
       
   594             for (int i=0; i<services.length; i++) {
       
   595                 try {
       
   596                     if (services[i].
       
   597                         getUnsupportedAttributes(flavor, requestSet) == null) {
       
   598                         matchingServices.add(services[i]);
       
   599                     }
       
   600                 } catch (IllegalArgumentException e) {
       
   601                 }
       
   602             }
       
   603             services = new PrintService[matchingServices.size()];
       
   604             return matchingServices.toArray(services);
       
   605 
       
   606         } else {
       
   607             // We only need to compare 1 PrintService because all
       
   608             // UnixPrintServices are the same anyway.  We will not use
       
   609             // default PrintService because it might be null.
       
   610             PrintService service = services[0];
       
   611             if ((flavor == null ||
       
   612                  service.isDocFlavorSupported(flavor)) &&
       
   613                  service.getUnsupportedAttributes(flavor, requestSet) == null)
       
   614             {
       
   615                 return services;
       
   616             } else {
       
   617                 return new PrintService[0];
       
   618             }
       
   619         }
       
   620     }
       
   621 
       
   622     /*
       
   623      * return empty array as don't support multi docs
       
   624      */
       
   625     public MultiDocPrintService[]
       
   626         getMultiDocPrintServices(DocFlavor[] flavors,
       
   627                                  AttributeSet attributes) {
       
   628         SecurityManager security = System.getSecurityManager();
       
   629         if (security != null) {
       
   630           security.checkPrintJobAccess();
       
   631         }
       
   632         return new MultiDocPrintService[0];
       
   633     }
       
   634 
       
   635 
       
   636     public synchronized PrintService getDefaultPrintService() {
       
   637         SecurityManager security = System.getSecurityManager();
       
   638         if (security != null) {
       
   639           security.checkPrintJobAccess();
       
   640         }
       
   641 
       
   642         // clear defaultPrintService
       
   643         defaultPrintService = null;
       
   644         String psuri = null;
       
   645 
       
   646         IPPPrintService.debug_println("isRunning ? "+
       
   647                                       (CUPSPrinter.isCupsRunning()));
       
   648         if (CUPSPrinter.isCupsRunning()) {
       
   649             String[] printerInfo = CUPSPrinter.getDefaultPrinter();
       
   650             if (printerInfo != null && printerInfo.length >= 2) {
       
   651                 defaultPrinter = printerInfo[0];
       
   652                 psuri = printerInfo[1];
       
   653             }
       
   654         } else {
       
   655             if (isMac() || isSysV()) {
       
   656                 defaultPrinter = getDefaultPrinterNameSysV();
       
   657             } else if (isAIX()) {
       
   658                 defaultPrinter = getDefaultPrinterNameAIX();
       
   659             } else {
       
   660                 defaultPrinter = getDefaultPrinterNameBSD();
       
   661             }
       
   662         }
       
   663         if (defaultPrinter == null) {
       
   664             return null;
       
   665         }
       
   666         defaultPrintService = null;
       
   667         if (printServices != null) {
       
   668             for (int j=0; j<printServices.length; j++) {
       
   669                 if (defaultPrinter.equals(getPrinterDestName(printServices[j]))) {
       
   670                     defaultPrintService = printServices[j];
       
   671                     break;
       
   672                 }
       
   673             }
       
   674         }
       
   675         if (defaultPrintService == null) {
       
   676             if (CUPSPrinter.isCupsRunning()) {
       
   677                 try {
       
   678                     PrintService defaultPS;
       
   679                     if ((psuri != null) && !psuri.startsWith("file")) {
       
   680                         defaultPS = new IPPPrintService(defaultPrinter,
       
   681                                                         psuri, true);
       
   682                     } else {
       
   683                         defaultPS = new IPPPrintService(defaultPrinter,
       
   684                                             new URL("http://"+
       
   685                                                     CUPSPrinter.getServer()+":"+
       
   686                                                     CUPSPrinter.getPort()+"/"+
       
   687                                                     defaultPrinter));
       
   688                     }
       
   689                     defaultPrintService = defaultPS;
       
   690                 } catch (Exception e) {
       
   691                 }
       
   692             } else {
       
   693                 defaultPrintService = new UnixPrintService(defaultPrinter);
       
   694             }
       
   695         }
       
   696 
       
   697         return defaultPrintService;
       
   698     }
       
   699 
       
   700     public synchronized void
       
   701         getServicesInbackground(BackgroundLookupListener listener) {
       
   702         if (printServices != null) {
       
   703             listener.notifyServices(printServices);
       
   704         } else {
       
   705             if (lookupListeners == null) {
       
   706                 lookupListeners = new Vector<>();
       
   707                 lookupListeners.add(listener);
       
   708                 Thread lookupThread = new Thread(this);
       
   709                 lookupThread.start();
       
   710             } else {
       
   711                 lookupListeners.add(listener);
       
   712             }
       
   713         }
       
   714     }
       
   715 
       
   716     /* This method isn't used in most cases because we rely on code in
       
   717      * javax.print.PrintServiceLookup. This is needed just for the cases
       
   718      * where those interfaces are by-passed.
       
   719      */
       
   720     private PrintService[] copyOf(PrintService[] inArr) {
       
   721         if (inArr == null || inArr.length == 0) {
       
   722             return inArr;
       
   723         } else {
       
   724             PrintService []outArr = new PrintService[inArr.length];
       
   725             System.arraycopy(inArr, 0, outArr, 0, inArr.length);
       
   726             return outArr;
       
   727         }
       
   728     }
       
   729 
       
   730     public void run() {
       
   731         PrintService[] services = getPrintServices();
       
   732         synchronized (this) {
       
   733             BackgroundLookupListener listener;
       
   734             for (int i=0; i<lookupListeners.size(); i++) {
       
   735                 listener = lookupListeners.elementAt(i);
       
   736                 listener.notifyServices(copyOf(services));
       
   737             }
       
   738             lookupListeners = null;
       
   739         }
       
   740     }
       
   741 
       
   742     private String getDefaultPrinterNameBSD() {
       
   743         if (cmdIndex == UNINITIALIZED) {
       
   744             cmdIndex = getBSDCommandIndex();
       
   745         }
       
   746         String[] names = execCmd(lpcFirstCom[cmdIndex]);
       
   747         if (names == null || names.length == 0) {
       
   748             return null;
       
   749         }
       
   750 
       
   751         if ((cmdIndex==BSD_LPD_NG) &&
       
   752             (names[0].startsWith("missingprinter"))) {
       
   753             return null;
       
   754         }
       
   755         return names[0];
       
   756     }
       
   757 
       
   758     private PrintService getNamedPrinterNameBSD(String name) {
       
   759       if (cmdIndex == UNINITIALIZED) {
       
   760         cmdIndex = getBSDCommandIndex();
       
   761       }
       
   762       String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex];
       
   763       String[] result = execCmd(command);
       
   764 
       
   765       if (result == null || !(result[0].equals(name))) {
       
   766           return null;
       
   767       }
       
   768       return new UnixPrintService(name);
       
   769     }
       
   770 
       
   771     private String[] getAllPrinterNamesBSD() {
       
   772         if (cmdIndex == UNINITIALIZED) {
       
   773             cmdIndex = getBSDCommandIndex();
       
   774         }
       
   775         String[] names = execCmd(lpcAllCom[cmdIndex]);
       
   776         if (names == null || names.length == 0) {
       
   777           return null;
       
   778         }
       
   779         return names;
       
   780     }
       
   781 
       
   782     static String getDefaultPrinterNameSysV() {
       
   783         String defaultPrinter = "lp";
       
   784         String command = "/usr/bin/lpstat -d";
       
   785 
       
   786         String [] names = execCmd(command);
       
   787         if (names == null || names.length == 0) {
       
   788             return defaultPrinter;
       
   789         } else {
       
   790             int index = names[0].indexOf(":");
       
   791             if (index == -1  || (names[0].length() <= index+1)) {
       
   792                 return null;
       
   793             } else {
       
   794                 String name = names[0].substring(index+1).trim();
       
   795                 if (name.length() == 0) {
       
   796                     return null;
       
   797                 } else {
       
   798                     return name;
       
   799                 }
       
   800             }
       
   801         }
       
   802     }
       
   803 
       
   804     private PrintService getNamedPrinterNameSysV(String name) {
       
   805 
       
   806         String command = "/usr/bin/lpstat -v " + name;
       
   807         String []result = execCmd(command);
       
   808 
       
   809         if (result == null || result[0].indexOf("unknown printer") > 0) {
       
   810             return null;
       
   811         } else {
       
   812             return new UnixPrintService(name);
       
   813         }
       
   814     }
       
   815 
       
   816     private String[] getAllPrinterNamesSysV() {
       
   817         String defaultPrinter = "lp";
       
   818         String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort";
       
   819 
       
   820         String [] names = execCmd(command);
       
   821         ArrayList<String> printerNames = new ArrayList<>();
       
   822         for (int i=0; i < names.length; i++) {
       
   823             if (!names[i].equals("_default") &&
       
   824                 !names[i].equals(defaultPrinter) &&
       
   825                 !names[i].equals("")) {
       
   826                 printerNames.add(names[i]);
       
   827             }
       
   828         }
       
   829         return printerNames.toArray(new String[printerNames.size()]);
       
   830     }
       
   831 
       
   832     private String getDefaultPrinterNameAIX() {
       
   833         String[] names = execCmd(lpNameComAix[aix_lpstat_d]);
       
   834         // Remove headers and bogus entries added by remote printers.
       
   835         names = UnixPrintService.filterPrinterNamesAIX(names);
       
   836         if (names == null || names.length != 1) {
       
   837             // No default printer found
       
   838             return null;
       
   839         } else {
       
   840             return names[0];
       
   841         }
       
   842     }
       
   843 
       
   844     private PrintService getNamedPrinterNameAIX(String name) {
       
   845         // On AIX there should be no blank after '-v'.
       
   846         String[] result = execCmd(lpNameComAix[aix_lpstat_v] + name);
       
   847         // Remove headers and bogus entries added by remote printers.
       
   848         result = UnixPrintService.filterPrinterNamesAIX(result);
       
   849         if (result == null || result.length != 1) {
       
   850             return null;
       
   851         } else {
       
   852             return new UnixPrintService(name);
       
   853         }
       
   854     }
       
   855 
       
   856     private String[] getAllPrinterNamesAIX() {
       
   857         // Determine all printers of the system.
       
   858         String [] names = execCmd(lpNameComAix[aix_defaultPrinterEnumeration]);
       
   859 
       
   860         // Remove headers and bogus entries added by remote printers.
       
   861         names = UnixPrintService.filterPrinterNamesAIX(names);
       
   862 
       
   863         ArrayList<String> printerNames = new ArrayList<String>();
       
   864         for ( int i=0; i < names.length; i++) {
       
   865             printerNames.add(names[i]);
       
   866         }
       
   867         return printerNames.toArray(new String[printerNames.size()]);
       
   868     }
       
   869 
       
   870     static String[] execCmd(final String command) {
       
   871         ArrayList<String> results = null;
       
   872         try {
       
   873             final String[] cmd = new String[3];
       
   874             if (isSysV() || isAIX()) {
       
   875                 cmd[0] = "/usr/bin/sh";
       
   876                 cmd[1] = "-c";
       
   877                 cmd[2] = "env LC_ALL=C " + command;
       
   878             } else {
       
   879                 cmd[0] = "/bin/sh";
       
   880                 cmd[1] = "-c";
       
   881                 cmd[2] = "LC_ALL=C " + command;
       
   882             }
       
   883 
       
   884             results = AccessController.doPrivileged(
       
   885                 new PrivilegedExceptionAction<ArrayList<String>>() {
       
   886                     public ArrayList<String> run() throws IOException {
       
   887 
       
   888                         Process proc;
       
   889                         BufferedReader bufferedReader = null;
       
   890                         File f = Files.createTempFile("prn","xc").toFile();
       
   891                         cmd[2] = cmd[2]+">"+f.getAbsolutePath();
       
   892 
       
   893                         proc = Runtime.getRuntime().exec(cmd);
       
   894                         try {
       
   895                             boolean done = false; // in case of interrupt.
       
   896                             while (!done) {
       
   897                                 try {
       
   898                                     proc.waitFor();
       
   899                                     done = true;
       
   900                                 } catch (InterruptedException e) {
       
   901                                 }
       
   902                             }
       
   903 
       
   904                             if (proc.exitValue() == 0) {
       
   905                                 FileReader reader = new FileReader(f);
       
   906                                 bufferedReader = new BufferedReader(reader);
       
   907                                 String line;
       
   908                                 ArrayList<String> results = new ArrayList<>();
       
   909                                 while ((line = bufferedReader.readLine())
       
   910                                        != null) {
       
   911                                     results.add(line);
       
   912                                 }
       
   913                                 return results;
       
   914                             }
       
   915                         } finally {
       
   916                             f.delete();
       
   917                             // promptly close all streams.
       
   918                             if (bufferedReader != null) {
       
   919                                 bufferedReader.close();
       
   920                             }
       
   921                             proc.getInputStream().close();
       
   922                             proc.getErrorStream().close();
       
   923                             proc.getOutputStream().close();
       
   924                         }
       
   925                         return null;
       
   926                     }
       
   927                 });
       
   928         } catch (PrivilegedActionException e) {
       
   929         }
       
   930         if (results == null) {
       
   931             return new String[0];
       
   932         } else {
       
   933             return results.toArray(new String[results.size()]);
       
   934         }
       
   935     }
       
   936 
       
   937     private class PrinterChangeListener extends Thread {
       
   938 
       
   939         public void run() {
       
   940             int refreshSecs;
       
   941             while (true) {
       
   942                 try {
       
   943                     refreshServices();
       
   944                 } catch (Exception se) {
       
   945                     IPPPrintService.debug_println(debugPrefix+"Exception in refresh thread.");
       
   946                     break;
       
   947                 }
       
   948 
       
   949                 if ((printServices != null) &&
       
   950                     (printServices.length > minRefreshTime)) {
       
   951                     // compute new refresh time 1 printer = 1 sec
       
   952                     refreshSecs = printServices.length;
       
   953                 } else {
       
   954                     refreshSecs = minRefreshTime;
       
   955                 }
       
   956                 try {
       
   957                     sleep(refreshSecs * 1000);
       
   958                 } catch (InterruptedException e) {
       
   959                     break;
       
   960                 }
       
   961             }
       
   962         }
       
   963     }
       
   964 }