Path: blob/master/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java
41152 views
/*1* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.print;2627import java.io.BufferedReader;28import java.io.FileInputStream;29import java.io.InputStream;30import java.io.InputStreamReader;31import java.io.IOException;32import java.util.ArrayList;33import java.util.Vector;34import java.security.AccessController;35import java.security.PrivilegedActionException;36import java.security.PrivilegedExceptionAction;37import javax.print.DocFlavor;38import javax.print.MultiDocPrintService;39import javax.print.PrintService;40import javax.print.PrintServiceLookup;41import javax.print.attribute.Attribute;42import javax.print.attribute.AttributeSet;43import javax.print.attribute.HashPrintRequestAttributeSet;44import javax.print.attribute.HashPrintServiceAttributeSet;45import javax.print.attribute.PrintRequestAttribute;46import javax.print.attribute.PrintRequestAttributeSet;47import javax.print.attribute.PrintServiceAttribute;48import javax.print.attribute.PrintServiceAttributeSet;49import javax.print.attribute.standard.PrinterName;50import javax.print.attribute.standard.PrinterURI;51import java.io.File;52import java.io.FileReader;53import java.net.URL;54import java.nio.file.Files;5556/*57* Remind: This class uses solaris commands. We also need a linux58* version59*/60@SuppressWarnings("removal")61public class PrintServiceLookupProvider extends PrintServiceLookup62implements BackgroundServiceLookup, Runnable {6364/* Remind: the current implementation is static, as its assumed65* its preferable to minimize creation of PrintService instances.66* Later we should add logic to add/remove services on the fly which67* will take a hit of needing to regather the list of services.68*/69private String defaultPrinter;70private PrintService defaultPrintService;71private PrintService[] printServices; /* includes the default printer */72private Vector<BackgroundLookupListener> lookupListeners = null;73private static String debugPrefix = "PrintServiceLookupProvider>> ";74private static boolean pollServices = true;75private static final int DEFAULT_MINREFRESH = 120; // 2 minutes76private static int minRefreshTime = DEFAULT_MINREFRESH;777879static String osname;8081// List of commands used to deal with the printer queues on AIX82String[] 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};88private static final int aix_lsallq = 0;89private static final int aix_lpstat_p = 1;90private static final int aix_lpstat_d = 2;91private static final int aix_lpstat_v = 3;92private static int aix_defaultPrinterEnumeration = aix_lsallq;9394static {95/* The system property "sun.java2d.print.polling"96* can be used to force the printing code to poll or not poll97* for PrintServices.98*/99String pollStr = java.security.AccessController.doPrivileged(100new sun.security.action.GetPropertyAction("sun.java2d.print.polling"));101102if (pollStr != null) {103if (pollStr.equalsIgnoreCase("true")) {104pollServices = true;105} else if (pollStr.equalsIgnoreCase("false")) {106pollServices = false;107}108}109110/* 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*/114String refreshTimeStr = java.security.AccessController.doPrivileged(115new sun.security.action.GetPropertyAction(116"sun.java2d.print.minRefreshTime"));117118if (refreshTimeStr != null) {119try {120minRefreshTime = (Integer.valueOf(refreshTimeStr)).intValue();121} catch (NumberFormatException e) {122}123if (minRefreshTime < DEFAULT_MINREFRESH) {124minRefreshTime = DEFAULT_MINREFRESH;125}126}127128osname = java.security.AccessController.doPrivileged(129new sun.security.action.GetPropertyAction("os.name"));130131/* The system property "sun.java2d.print.aix.lpstat"132* can be used to force the usage of 'lpstat -p' to enumerate all133* printer queues. By default we use 'lsallq', because 'lpstat -p' can134* take lots of time if thousands of printers are attached to a server.135*/136if (isAIX()) {137String aixPrinterEnumerator = java.security.AccessController.doPrivileged(138new sun.security.action.GetPropertyAction("sun.java2d.print.aix.lpstat"));139140if (aixPrinterEnumerator != null) {141if (aixPrinterEnumerator.equalsIgnoreCase("lpstat")) {142aix_defaultPrinterEnumeration = aix_lpstat_p;143} else if (aixPrinterEnumerator.equalsIgnoreCase("lsallq")) {144aix_defaultPrinterEnumeration = aix_lsallq;145}146}147}148}149150static boolean isMac() {151return osname.startsWith("Mac");152}153154static boolean isLinux() {155return (osname.equals("Linux"));156}157158static boolean isBSD() {159return (osname.equals("Linux") ||160osname.contains("OS X"));161}162163static boolean isAIX() {164return osname.equals("AIX");165}166167static final int UNINITIALIZED = -1;168static final int BSD_LPD = 0;169static final int BSD_LPD_NG = 1;170171static int cmdIndex = UNINITIALIZED;172173String[] lpcFirstCom = {174"/usr/sbin/lpc status | grep : | sed -ne '1,1 s/://p'",175"/usr/sbin/lpc status | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'"176};177178String[] lpcAllCom = {179"/usr/sbin/lpc status all | grep : | sed -e 's/://'",180"/usr/sbin/lpc status all | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}' | sort"181};182183String[] lpcNameCom = {184"| grep : | sed -ne 's/://p'",185"| grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'"186};187188189static int getBSDCommandIndex() {190String command = "/usr/sbin/lpc status all";191String[] names = execCmd(command);192193if ((names == null) || (names.length == 0)) {194return BSD_LPD_NG;195}196197for (int i=0; i<names.length; i++) {198if (names[i].indexOf('@') != -1) {199return BSD_LPD_NG;200}201}202203return BSD_LPD;204}205206207public PrintServiceLookupProvider() {208// start the printer listener thread209if (pollServices) {210Thread thr = new Thread(null, new PrinterChangeListener(),211"PrinterListener", 0, false);212thr.setDaemon(true);213thr.start();214IPPPrintService.debug_println(debugPrefix+"polling turned on");215}216}217218/* Want the PrintService which is default print service to have219* equality of reference with the equivalent in list of print services220* This isn't required by the API and there's a risk doing this will221* lead people to assume its guaranteed.222*/223public synchronized PrintService[] getPrintServices() {224SecurityManager security = System.getSecurityManager();225if (security != null) {226security.checkPrintJobAccess();227}228229if (printServices == null || !pollServices) {230refreshServices();231}232if (printServices == null) {233return new PrintService[0];234} else {235return printServices.clone();236}237}238239private int addPrintServiceToList(ArrayList<PrintService> printerList, PrintService ps) {240int index = printerList.indexOf(ps);241// Check if PrintService with same name is already in the list.242if (CUPSPrinter.isCupsRunning() && index != -1) {243// Bug in Linux: Duplicate entry of a remote printer244// and treats it as local printer but it is returning wrong245// information when queried using IPP. Workaround is to remove it.246// Even CUPS ignores these entries as shown in lpstat or using247// their web configuration.248PrinterURI uri = ps.getAttribute(PrinterURI.class);249if (uri.getURI().getHost().equals("localhost")) {250IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, ignoring the new local printer: "+ps);251return index; // Do not add this.252}253PrintService oldPS = printerList.get(index);254uri = oldPS.getAttribute(PrinterURI.class);255if (uri.getURI().getHost().equals("localhost")) {256IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, removing existing local printer: "+oldPS);257printerList.remove(oldPS);258} else {259return index;260}261}262printerList.add(ps);263return (printerList.size() - 1);264}265266267// refreshes "printServices"268public synchronized void refreshServices() {269/* excludes the default printer */270String[] printers = null; // array of printer names271String[] printerURIs = null; //array of printer URIs272273try {274getDefaultPrintService();275} catch (Throwable t) {276IPPPrintService.debug_println(debugPrefix+277"Exception getting default printer : " + t);278}279if (CUPSPrinter.isCupsRunning()) {280try {281printerURIs = CUPSPrinter.getAllPrinters();282IPPPrintService.debug_println("CUPS URIs = " + printerURIs);283if (printerURIs != null) {284for (int p = 0; p < printerURIs.length; p++) {285IPPPrintService.debug_println("URI="+printerURIs[p]);286}287}288} catch (Throwable t) {289IPPPrintService.debug_println(debugPrefix+290"Exception getting all CUPS printers : " + t);291}292if ((printerURIs != null) && (printerURIs.length > 0)) {293printers = new String[printerURIs.length];294for (int i=0; i<printerURIs.length; i++) {295int lastIndex = printerURIs[i].lastIndexOf("/");296printers[i] = printerURIs[i].substring(lastIndex+1);297}298}299} else {300if (isMac()) {301printers = getAllPrinterNamesSysV();302} else if (isAIX()) {303printers = getAllPrinterNamesAIX();304} else { //BSD305printers = getAllPrinterNamesBSD();306}307}308309if (printers == null) {310if (defaultPrintService != null) {311printServices = new PrintService[1];312printServices[0] = defaultPrintService;313} else {314printServices = null;315}316return;317}318319ArrayList<PrintService> printerList = new ArrayList<>();320int defaultIndex = -1;321for (int p=0; p<printers.length; p++) {322if (printers[p] == null) {323continue;324}325if ((defaultPrintService != null)326&& printers[p].equals(getPrinterDestName(defaultPrintService))) {327defaultIndex = addPrintServiceToList(printerList, defaultPrintService);328} else {329if (printServices == null) {330IPPPrintService.debug_println(debugPrefix+331"total# of printers = "+printers.length);332333if (CUPSPrinter.isCupsRunning()) {334try {335addPrintServiceToList(printerList,336new IPPPrintService(printers[p],337printerURIs[p],338true));339} catch (Exception e) {340IPPPrintService.debug_println(debugPrefix+341" getAllPrinters Exception "+342e);343344}345} else {346printerList.add(new UnixPrintService(printers[p]));347}348} else {349int j;350for (j=0; j<printServices.length; j++) {351if (printServices[j] != null) {352if (printers[p].equals(getPrinterDestName(printServices[j]))) {353printerList.add(printServices[j]);354printServices[j] = null;355break;356}357}358}359360if (j == printServices.length) { // not found?361if (CUPSPrinter.isCupsRunning()) {362try {363addPrintServiceToList(printerList,364new IPPPrintService(printers[p],365printerURIs[p],366true));367} catch (Exception e) {368IPPPrintService.debug_println(debugPrefix+369" getAllPrinters Exception "+370e);371372}373} else {374printerList.add(new UnixPrintService(printers[p]));375}376}377}378}379}380381// Look for deleted services and invalidate these382if (printServices != null) {383for (int j=0; j < printServices.length; j++) {384if ((printServices[j] instanceof UnixPrintService) &&385(!printServices[j].equals(defaultPrintService))) {386((UnixPrintService)printServices[j]).invalidateService();387}388}389}390391//if defaultService is not found in printerList392if (defaultIndex == -1 && defaultPrintService != null) {393defaultIndex = addPrintServiceToList(printerList, defaultPrintService);394}395396printServices = printerList.toArray(new PrintService[] {});397398// swap default with the first in the list399if (defaultIndex > 0) {400PrintService saveService = printServices[0];401printServices[0] = printServices[defaultIndex];402printServices[defaultIndex] = saveService;403}404}405406private boolean matchesAttributes(PrintService service,407PrintServiceAttributeSet attributes) {408409Attribute [] attrs = attributes.toArray();410for (int i=0; i<attrs.length; i++) {411@SuppressWarnings("unchecked")412Attribute serviceAttr413= service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory());414if (serviceAttr == null || !serviceAttr.equals(attrs[i])) {415return false;416}417}418return true;419}420421/* This checks for validity of the printer name before passing as422* parameter to a shell command.423*/424private boolean checkPrinterName(String s) {425char c;426427for (int i=0; i < s.length(); i++) {428c = s.charAt(i);429if (Character.isLetterOrDigit(c) ||430c == '-' || c == '_' || c == '.' || c == '/') {431continue;432} else {433return false;434}435}436return true;437}438439/*440* Gets the printer name compatible with the list of printers returned by441* the system when we query default or all the available printers.442*/443private String getPrinterDestName(PrintService ps) {444if (isMac()) {445return ((IPPPrintService)ps).getDest();446}447return ps.getName();448}449450/* On a network with many (hundreds) of network printers, it451* can save several seconds if you know all you want is a particular452* printer, to ask for that printer rather than retrieving all printers.453*/454private PrintService getServiceByName(PrinterName nameAttr) {455String name = nameAttr.getValue();456if (name == null || name.isEmpty() || !checkPrinterName(name)) {457return null;458}459/* check if all printers are already available */460if (printServices != null) {461for (PrintService printService : printServices) {462PrinterName printerName = printService.getAttribute(PrinterName.class);463if (printerName.getValue().equals(name)) {464return printService;465}466}467}468/* take CUPS into account first */469if (CUPSPrinter.isCupsRunning()) {470try {471return new IPPPrintService(name,472new URL("http://"+473CUPSPrinter.getServer()+":"+474CUPSPrinter.getPort()+"/"+475name));476} catch (Exception e) {477IPPPrintService.debug_println(debugPrefix+478" getServiceByName Exception "+479e);480}481}482/* fallback if nothing not having a printer at this point */483PrintService printer = null;484if (isMac()) {485printer = getNamedPrinterNameSysV(name);486} else if (isAIX()) {487printer = getNamedPrinterNameAIX(name);488} else {489printer = getNamedPrinterNameBSD(name);490}491return printer;492}493494private PrintService[]495getPrintServices(PrintServiceAttributeSet serviceSet) {496497if (serviceSet == null || serviceSet.isEmpty()) {498return getPrintServices();499}500501/* Typically expect that if a service attribute is specified that502* its a printer name and there ought to be only one match.503* Directly retrieve that service and confirm504* that it meets the other requirements.505* If printer name isn't mentioned then go a slow path checking506* all printers if they meet the reqiremements.507*/508PrintService[] services;509PrinterName name = (PrinterName)serviceSet.get(PrinterName.class);510PrintService defService;511if (name != null && (defService = getDefaultPrintService()) != null) {512/* To avoid execing a unix command see if the client is asking513* for the default printer by name, since we already have that514* initialised.515*/516517PrinterName defName = defService.getAttribute(PrinterName.class);518519if (defName != null && name.equals(defName)) {520if (matchesAttributes(defService, serviceSet)) {521services = new PrintService[1];522services[0] = defService;523return services;524} else {525return new PrintService[0];526}527} else {528/* Its not the default service */529PrintService service = getServiceByName(name);530if (service != null &&531matchesAttributes(service, serviceSet)) {532services = new PrintService[1];533services[0] = service;534return services;535} else {536return new PrintService[0];537}538}539} else {540/* specified service attributes don't include a name.*/541Vector<PrintService> matchedServices = new Vector<>();542services = getPrintServices();543for (int i = 0; i< services.length; i++) {544if (matchesAttributes(services[i], serviceSet)) {545matchedServices.add(services[i]);546}547}548services = new PrintService[matchedServices.size()];549for (int i = 0; i< services.length; i++) {550services[i] = matchedServices.elementAt(i);551}552return services;553}554}555556/*557* If service attributes are specified then there must be additional558* filtering.559*/560public PrintService[] getPrintServices(DocFlavor flavor,561AttributeSet attributes) {562SecurityManager security = System.getSecurityManager();563if (security != null) {564security.checkPrintJobAccess();565}566PrintRequestAttributeSet requestSet = null;567PrintServiceAttributeSet serviceSet = null;568569if (attributes != null && !attributes.isEmpty()) {570571requestSet = new HashPrintRequestAttributeSet();572serviceSet = new HashPrintServiceAttributeSet();573574Attribute[] attrs = attributes.toArray();575for (int i=0; i<attrs.length; i++) {576if (attrs[i] instanceof PrintRequestAttribute) {577requestSet.add(attrs[i]);578} else if (attrs[i] instanceof PrintServiceAttribute) {579serviceSet.add(attrs[i]);580}581}582}583584PrintService[] services = getPrintServices(serviceSet);585if (services.length == 0) {586return services;587}588589if (CUPSPrinter.isCupsRunning()) {590ArrayList<PrintService> matchingServices = new ArrayList<>();591for (int i=0; i<services.length; i++) {592try {593if (services[i].594getUnsupportedAttributes(flavor, requestSet) == null) {595matchingServices.add(services[i]);596}597} catch (IllegalArgumentException e) {598}599}600services = new PrintService[matchingServices.size()];601return matchingServices.toArray(services);602603} else {604// We only need to compare 1 PrintService because all605// UnixPrintServices are the same anyway. We will not use606// default PrintService because it might be null.607PrintService service = services[0];608if ((flavor == null ||609service.isDocFlavorSupported(flavor)) &&610service.getUnsupportedAttributes(flavor, requestSet) == null)611{612return services;613} else {614return new PrintService[0];615}616}617}618619/*620* return empty array as don't support multi docs621*/622public MultiDocPrintService[]623getMultiDocPrintServices(DocFlavor[] flavors,624AttributeSet attributes) {625SecurityManager security = System.getSecurityManager();626if (security != null) {627security.checkPrintJobAccess();628}629return new MultiDocPrintService[0];630}631632633public synchronized PrintService getDefaultPrintService() {634SecurityManager security = System.getSecurityManager();635if (security != null) {636security.checkPrintJobAccess();637}638639// clear defaultPrintService640defaultPrintService = null;641String psuri = null;642643IPPPrintService.debug_println("isRunning ? "+644(CUPSPrinter.isCupsRunning()));645if (CUPSPrinter.isCupsRunning()) {646String[] printerInfo = CUPSPrinter.getDefaultPrinter();647if (printerInfo != null && printerInfo.length >= 2) {648defaultPrinter = printerInfo[0];649psuri = printerInfo[1];650}651} else {652if (isMac()) {653defaultPrinter = getDefaultPrinterNameSysV();654} else if (isAIX()) {655defaultPrinter = getDefaultPrinterNameAIX();656} else {657defaultPrinter = getDefaultPrinterNameBSD();658}659}660if (defaultPrinter == null) {661return null;662}663defaultPrintService = null;664if (printServices != null) {665for (int j=0; j<printServices.length; j++) {666if (defaultPrinter.equals(getPrinterDestName(printServices[j]))) {667defaultPrintService = printServices[j];668break;669}670}671}672if (defaultPrintService == null) {673if (CUPSPrinter.isCupsRunning()) {674try {675PrintService defaultPS;676if ((psuri != null) && !psuri.startsWith("file")) {677defaultPS = new IPPPrintService(defaultPrinter,678psuri, true);679} else {680defaultPS = new IPPPrintService(defaultPrinter,681new URL("http://"+682CUPSPrinter.getServer()+":"+683CUPSPrinter.getPort()+"/"+684defaultPrinter));685}686defaultPrintService = defaultPS;687} catch (Exception e) {688}689} else {690defaultPrintService = new UnixPrintService(defaultPrinter);691}692}693694return defaultPrintService;695}696697public synchronized void698getServicesInbackground(BackgroundLookupListener listener) {699if (printServices != null) {700listener.notifyServices(printServices);701} else {702if (lookupListeners == null) {703lookupListeners = new Vector<>();704lookupListeners.add(listener);705Thread lookupThread = new Thread(this);706lookupThread.start();707} else {708lookupListeners.add(listener);709}710}711}712713/* This method isn't used in most cases because we rely on code in714* javax.print.PrintServiceLookup. This is needed just for the cases715* where those interfaces are by-passed.716*/717private PrintService[] copyOf(PrintService[] inArr) {718if (inArr == null || inArr.length == 0) {719return inArr;720} else {721PrintService []outArr = new PrintService[inArr.length];722System.arraycopy(inArr, 0, outArr, 0, inArr.length);723return outArr;724}725}726727public void run() {728PrintService[] services = getPrintServices();729synchronized (this) {730BackgroundLookupListener listener;731for (int i=0; i<lookupListeners.size(); i++) {732listener = lookupListeners.elementAt(i);733listener.notifyServices(copyOf(services));734}735lookupListeners = null;736}737}738739private String getDefaultPrinterNameBSD() {740if (cmdIndex == UNINITIALIZED) {741cmdIndex = getBSDCommandIndex();742}743String[] names = execCmd(lpcFirstCom[cmdIndex]);744if (names == null || names.length == 0) {745return null;746}747748if ((cmdIndex==BSD_LPD_NG) &&749(names[0].startsWith("missingprinter"))) {750return null;751}752return names[0];753}754755private PrintService getNamedPrinterNameBSD(String name) {756if (cmdIndex == UNINITIALIZED) {757cmdIndex = getBSDCommandIndex();758}759String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex];760String[] result = execCmd(command);761762if (result == null || !(result[0].equals(name))) {763return null;764}765return new UnixPrintService(name);766}767768private String[] getAllPrinterNamesBSD() {769if (cmdIndex == UNINITIALIZED) {770cmdIndex = getBSDCommandIndex();771}772String[] names = execCmd(lpcAllCom[cmdIndex]);773if (names == null || names.length == 0) {774return null;775}776return names;777}778779static String getDefaultPrinterNameSysV() {780String defaultPrinter = "lp";781String command = "/usr/bin/lpstat -d";782783String [] names = execCmd(command);784if (names == null || names.length == 0) {785return defaultPrinter;786} else {787int index = names[0].indexOf(":");788if (index == -1 || (names[0].length() <= index+1)) {789return null;790} else {791String name = names[0].substring(index+1).trim();792if (name.length() == 0) {793return null;794} else {795return name;796}797}798}799}800801private PrintService getNamedPrinterNameSysV(String name) {802803String command = "/usr/bin/lpstat -v " + name;804String []result = execCmd(command);805806if (result == null || result[0].indexOf("unknown printer") > 0) {807return null;808} else {809return new UnixPrintService(name);810}811}812813private String[] getAllPrinterNamesSysV() {814String defaultPrinter = "lp";815String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort";816817String [] names = execCmd(command);818ArrayList<String> printerNames = new ArrayList<>();819for (int i=0; i < names.length; i++) {820if (!names[i].equals("_default") &&821!names[i].equals(defaultPrinter) &&822!names[i].isEmpty()) {823printerNames.add(names[i]);824}825}826return printerNames.toArray(new String[printerNames.size()]);827}828829private String getDefaultPrinterNameAIX() {830String[] names = execCmd(lpNameComAix[aix_lpstat_d]);831// Remove headers and bogus entries added by remote printers.832names = UnixPrintService.filterPrinterNamesAIX(names);833if (names == null || names.length != 1) {834// No default printer found835return null;836} else {837return names[0];838}839}840841private PrintService getNamedPrinterNameAIX(String name) {842// On AIX there should be no blank after '-v'.843String[] result = execCmd(lpNameComAix[aix_lpstat_v] + name);844// Remove headers and bogus entries added by remote printers.845result = UnixPrintService.filterPrinterNamesAIX(result);846if (result == null || result.length != 1) {847return null;848} else {849return new UnixPrintService(name);850}851}852853private String[] getAllPrinterNamesAIX() {854// Determine all printers of the system.855String [] names = execCmd(lpNameComAix[aix_defaultPrinterEnumeration]);856857// Remove headers and bogus entries added by remote printers.858names = UnixPrintService.filterPrinterNamesAIX(names);859860ArrayList<String> printerNames = new ArrayList<String>();861for ( int i=0; i < names.length; i++) {862printerNames.add(names[i]);863}864return printerNames.toArray(new String[printerNames.size()]);865}866867static String[] execCmd(final String command) {868ArrayList<String> results = null;869try {870final String[] cmd = new String[3];871if (isAIX()) {872cmd[0] = "/usr/bin/sh";873cmd[1] = "-c";874cmd[2] = "env LC_ALL=C " + command;875} else {876cmd[0] = "/bin/sh";877cmd[1] = "-c";878cmd[2] = "LC_ALL=C " + command;879}880881results = AccessController.doPrivileged(882new PrivilegedExceptionAction<ArrayList<String>>() {883public ArrayList<String> run() throws IOException {884885Process proc;886BufferedReader bufferedReader = null;887File f = Files.createTempFile("prn","xc").toFile();888cmd[2] = cmd[2]+">"+f.getAbsolutePath();889890proc = Runtime.getRuntime().exec(cmd);891try {892boolean done = false; // in case of interrupt.893while (!done) {894try {895proc.waitFor();896done = true;897} catch (InterruptedException e) {898}899}900901if (proc.exitValue() == 0) {902FileReader reader = new FileReader(f);903bufferedReader = new BufferedReader(reader);904String line;905ArrayList<String> results = new ArrayList<>();906while ((line = bufferedReader.readLine())907!= null) {908results.add(line);909}910return results;911}912} finally {913f.delete();914// promptly close all streams.915if (bufferedReader != null) {916bufferedReader.close();917}918proc.getInputStream().close();919proc.getErrorStream().close();920proc.getOutputStream().close();921}922return null;923}924});925} catch (PrivilegedActionException e) {926}927if (results == null) {928return new String[0];929} else {930return results.toArray(new String[results.size()]);931}932}933934private class PrinterChangeListener implements Runnable {935936@Override937public void run() {938int refreshSecs;939while (true) {940try {941refreshServices();942} catch (Exception se) {943IPPPrintService.debug_println(debugPrefix+"Exception in refresh thread.");944break;945}946947if ((printServices != null) &&948(printServices.length > minRefreshTime)) {949// compute new refresh time 1 printer = 1 sec950refreshSecs = printServices.length;951} else {952refreshSecs = minRefreshTime;953}954try {955Thread.sleep(refreshSecs * 1000);956} catch (InterruptedException e) {957break;958}959}960}961}962}963964965