/*
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.print;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.print.DocFlavor;
import javax.print.MultiDocPrintService;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.Attribute;
import javax.print.attribute.AttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.HashPrintServiceAttributeSet;
import javax.print.attribute.PrintRequestAttribute;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.PrintServiceAttribute;
import javax.print.attribute.PrintServiceAttributeSet;
import javax.print.attribute.standard.PrinterName;
import javax.print.attribute.standard.PrinterURI;
import java.io.File;
import java.io.FileReader;
import java.net.URL;
import java.nio.file.Files;
/*
* Remind: This class uses solaris commands. We also need a linux
* version
*/
public class PrintServiceLookupProvider extends PrintServiceLookup
implements BackgroundServiceLookup, Runnable {
/* Remind: the current implementation is static, as its assumed
* its preferable to minimize creation of PrintService instances.
* Later we should add logic to add/remove services on the fly which
* will take a hit of needing to regather the list of services.
*/
private String defaultPrinter;
private PrintService defaultPrintService;
private PrintService[] printServices; /* includes the default printer */
private Vector<BackgroundLookupListener> lookupListeners = null;
private static String debugPrefix = "PrintServiceLookupProvider>> ";
private static boolean pollServices = true;
private static final int DEFAULT_MINREFRESH = 120; // 2 minutes
private static int minRefreshTime = DEFAULT_MINREFRESH;
static String osname;
// List of commands used to deal with the printer queues on AIX
String[] lpNameComAix = {
"/usr/bin/lsallq",
"/usr/bin/lpstat -W -p|/usr/bin/expand|/usr/bin/cut -f1 -d' '",
"/usr/bin/lpstat -W -d|/usr/bin/expand|/usr/bin/cut -f1 -d' '",
"/usr/bin/lpstat -W -v"
};
private static final int aix_lsallq = 0;
private static final int aix_lpstat_p = 1;
private static final int aix_lpstat_d = 2;
private static final int aix_lpstat_v = 3;
private static int aix_defaultPrinterEnumeration = aix_lsallq;
static {
/* The system property "sun.java2d.print.polling"
* can be used to force the printing code to poll or not poll
* for PrintServices.
*/
String pollStr = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.print.polling"));
if (pollStr != null) {
if (pollStr.equalsIgnoreCase("true")) {
pollServices = true;
} else if (pollStr.equalsIgnoreCase("false")) {
pollServices = false;
}
}
/* The system property "sun.java2d.print.minRefreshTime"
* can be used to specify minimum refresh time (in seconds)
* for polling PrintServices. The default is 120.
*/
String refreshTimeStr = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction(
"sun.java2d.print.minRefreshTime"));
if (refreshTimeStr != null) {
try {
minRefreshTime = (Integer.valueOf(refreshTimeStr)).intValue();
} catch (NumberFormatException e) {
}
if (minRefreshTime < DEFAULT_MINREFRESH) {
minRefreshTime = DEFAULT_MINREFRESH;
}
}
osname = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("os.name"));
/* The system property "sun.java2d.print.aix.lpstat"
* can be used to force the usage of 'lpstat -p' to enumerate all
* printer queues. By default we use 'lsallq', because 'lpstat -p' can
* take lots of time if thousands of printers are attached to a server.
*/
if (isAIX()) {
String aixPrinterEnumerator = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("sun.java2d.print.aix.lpstat"));
if (aixPrinterEnumerator != null) {
if (aixPrinterEnumerator.equalsIgnoreCase("lpstat")) {
aix_defaultPrinterEnumeration = aix_lpstat_p;
} else if (aixPrinterEnumerator.equalsIgnoreCase("lsallq")) {
aix_defaultPrinterEnumeration = aix_lsallq;
}
}
}
}
static boolean isMac() {
return osname.startsWith("Mac");
}
static boolean isSysV() {
return osname.equals("SunOS");
}
static boolean isLinux() {
return (osname.equals("Linux"));
}
static boolean isBSD() {
return (osname.equals("Linux") ||
osname.contains("OS X"));
}
static boolean isAIX() {
return osname.equals("AIX");
}
static final int UNINITIALIZED = -1;
static final int BSD_LPD = 0;
static final int BSD_LPD_NG = 1;
static int cmdIndex = UNINITIALIZED;
String[] lpcFirstCom = {
"/usr/sbin/lpc status | grep : | sed -ne '1,1 s/://p'",
"/usr/sbin/lpc status | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'"
};
String[] lpcAllCom = {
"/usr/sbin/lpc status all | grep : | sed -e 's/://'",
"/usr/sbin/lpc status all | grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}' | sort"
};
String[] lpcNameCom = {
"| grep : | sed -ne 's/://p'",
"| grep -E '^[ 0-9a-zA-Z_-]*@' | awk -F'@' '{print $1}'"
};
static int getBSDCommandIndex() {
String command = "/usr/sbin/lpc status all";
String[] names = execCmd(command);
if ((names == null) || (names.length == 0)) {
return BSD_LPD_NG;
}
for (int i=0; i<names.length; i++) {
if (names[i].indexOf('@') != -1) {
return BSD_LPD_NG;
}
}
return BSD_LPD;
}
public PrintServiceLookupProvider() {
// start the printer listener thread
if (pollServices) {
Thread thr = new Thread(null, new PrinterChangeListener(),
"PrinterListener", 0, false);
thr.setDaemon(true);
thr.start();
IPPPrintService.debug_println(debugPrefix+"polling turned on");
}
}
/* Want the PrintService which is default print service to have
* equality of reference with the equivalent in list of print services
* This isn't required by the API and there's a risk doing this will
* lead people to assume its guaranteed.
*/
public synchronized PrintService[] getPrintServices() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPrintJobAccess();
}
if (printServices == null || !pollServices) {
refreshServices();
}
if (printServices == null) {
return new PrintService[0];
} else {
return printServices.clone();
}
}
private int addPrintServiceToList(ArrayList<PrintService> printerList, PrintService ps) {
int index = printerList.indexOf(ps);
// Check if PrintService with same name is already in the list.
if (CUPSPrinter.isCupsRunning() && index != -1) {
// Bug in Linux: Duplicate entry of a remote printer
// and treats it as local printer but it is returning wrong
// information when queried using IPP. Workaround is to remove it.
// Even CUPS ignores these entries as shown in lpstat or using
// their web configuration.
PrinterURI uri = ps.getAttribute(PrinterURI.class);
if (uri.getURI().getHost().equals("localhost")) {
IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, ignoring the new local printer: "+ps);
return index; // Do not add this.
}
PrintService oldPS = printerList.get(index);
uri = oldPS.getAttribute(PrinterURI.class);
if (uri.getURI().getHost().equals("localhost")) {
IPPPrintService.debug_println(debugPrefix+"duplicate PrintService, removing existing local printer: "+oldPS);
printerList.remove(oldPS);
} else {
return index;
}
}
printerList.add(ps);
return (printerList.size() - 1);
}
// refreshes "printServices"
public synchronized void refreshServices() {
/* excludes the default printer */
String[] printers = null; // array of printer names
String[] printerURIs = null; //array of printer URIs
try {
getDefaultPrintService();
} catch (Throwable t) {
IPPPrintService.debug_println(debugPrefix+
"Exception getting default printer : " + t);
}
if (CUPSPrinter.isCupsRunning()) {
try {
printerURIs = CUPSPrinter.getAllPrinters();
IPPPrintService.debug_println("CUPS URIs = " + printerURIs);
if (printerURIs != null) {
for (int p = 0; p < printerURIs.length; p++) {
IPPPrintService.debug_println("URI="+printerURIs[p]);
}
}
} catch (Throwable t) {
IPPPrintService.debug_println(debugPrefix+
"Exception getting all CUPS printers : " + t);
}
if ((printerURIs != null) && (printerURIs.length > 0)) {
printers = new String[printerURIs.length];
for (int i=0; i<printerURIs.length; i++) {
int lastIndex = printerURIs[i].lastIndexOf("/");
printers[i] = printerURIs[i].substring(lastIndex+1);
}
}
} else {
if (isMac() || isSysV()) {
printers = getAllPrinterNamesSysV();
} else if (isAIX()) {
printers = getAllPrinterNamesAIX();
} else { //BSD
printers = getAllPrinterNamesBSD();
}
}
if (printers == null) {
if (defaultPrintService != null) {
printServices = new PrintService[1];
printServices[0] = defaultPrintService;
} else {
printServices = null;
}
return;
}
ArrayList<PrintService> printerList = new ArrayList<>();
int defaultIndex = -1;
for (int p=0; p<printers.length; p++) {
if (printers[p] == null) {
continue;
}
if ((defaultPrintService != null)
&& printers[p].equals(getPrinterDestName(defaultPrintService))) {
defaultIndex = addPrintServiceToList(printerList, defaultPrintService);
} else {
if (printServices == null) {
IPPPrintService.debug_println(debugPrefix+
"total# of printers = "+printers.length);
if (CUPSPrinter.isCupsRunning()) {
try {
addPrintServiceToList(printerList,
new IPPPrintService(printers[p],
printerURIs[p],
true));
} catch (Exception e) {
IPPPrintService.debug_println(debugPrefix+
" getAllPrinters Exception "+
e);
}
} else {
printerList.add(new UnixPrintService(printers[p]));
}
} else {
int j;
for (j=0; j<printServices.length; j++) {
if (printServices[j] != null) {
if (printers[p].equals(getPrinterDestName(printServices[j]))) {
printerList.add(printServices[j]);
printServices[j] = null;
break;
}
}
}
if (j == printServices.length) { // not found?
if (CUPSPrinter.isCupsRunning()) {
try {
addPrintServiceToList(printerList,
new IPPPrintService(printers[p],
printerURIs[p],
true));
} catch (Exception e) {
IPPPrintService.debug_println(debugPrefix+
" getAllPrinters Exception "+
e);
}
} else {
printerList.add(new UnixPrintService(printers[p]));
}
}
}
}
}
// Look for deleted services and invalidate these
if (printServices != null) {
for (int j=0; j < printServices.length; j++) {
if ((printServices[j] instanceof UnixPrintService) &&
(!printServices[j].equals(defaultPrintService))) {
((UnixPrintService)printServices[j]).invalidateService();
}
}
}
//if defaultService is not found in printerList
if (defaultIndex == -1 && defaultPrintService != null) {
defaultIndex = addPrintServiceToList(printerList, defaultPrintService);
}
printServices = printerList.toArray(new PrintService[] {});
// swap default with the first in the list
if (defaultIndex > 0) {
PrintService saveService = printServices[0];
printServices[0] = printServices[defaultIndex];
printServices[defaultIndex] = saveService;
}
}
private boolean matchesAttributes(PrintService service,
PrintServiceAttributeSet attributes) {
Attribute [] attrs = attributes.toArray();
for (int i=0; i<attrs.length; i++) {
@SuppressWarnings("unchecked")
Attribute serviceAttr
= service.getAttribute((Class<PrintServiceAttribute>)attrs[i].getCategory());
if (serviceAttr == null || !serviceAttr.equals(attrs[i])) {
return false;
}
}
return true;
}
/* This checks for validity of the printer name before passing as
* parameter to a shell command.
*/
private boolean checkPrinterName(String s) {
char c;
for (int i=0; i < s.length(); i++) {
c = s.charAt(i);
if (Character.isLetterOrDigit(c) ||
c == '-' || c == '_' || c == '.' || c == '/') {
continue;
} else {
return false;
}
}
return true;
}
/*
* Gets the printer name compatible with the list of printers returned by
* the system when we query default or all the available printers.
*/
private String getPrinterDestName(PrintService ps) {
if (isMac()) {
return ((IPPPrintService)ps).getDest();
}
return ps.getName();
}
/* On a network with many (hundreds) of network printers, it
* can save several seconds if you know all you want is a particular
* printer, to ask for that printer rather than retrieving all printers.
*/
private PrintService getServiceByName(PrinterName nameAttr) {
String name = nameAttr.getValue();
if (name == null || name.isEmpty() || !checkPrinterName(name)) {
return null;
}
/* check if all printers are already available */
if (printServices != null) {
for (PrintService printService : printServices) {
PrinterName printerName = printService.getAttribute(PrinterName.class);
if (printerName.getValue().equals(name)) {
return printService;
}
}
}
/* take CUPS into account first */
if (CUPSPrinter.isCupsRunning()) {
try {
return new IPPPrintService(name,
new URL("http://"+
CUPSPrinter.getServer()+":"+
CUPSPrinter.getPort()+"/"+
name));
} catch (Exception e) {
IPPPrintService.debug_println(debugPrefix+
" getServiceByName Exception "+
e);
}
}
/* fallback if nothing not having a printer at this point */
PrintService printer = null;
if (isMac() || isSysV()) {
printer = getNamedPrinterNameSysV(name);
} else if (isAIX()) {
printer = getNamedPrinterNameAIX(name);
} else {
printer = getNamedPrinterNameBSD(name);
}
return printer;
}
private PrintService[]
getPrintServices(PrintServiceAttributeSet serviceSet) {
if (serviceSet == null || serviceSet.isEmpty()) {
return getPrintServices();
}
/* Typically expect that if a service attribute is specified that
* its a printer name and there ought to be only one match.
* Directly retrieve that service and confirm
* that it meets the other requirements.
* If printer name isn't mentioned then go a slow path checking
* all printers if they meet the reqiremements.
*/
PrintService[] services;
PrinterName name = (PrinterName)serviceSet.get(PrinterName.class);
PrintService defService;
if (name != null && (defService = getDefaultPrintService()) != null) {
/* To avoid execing a unix command see if the client is asking
* for the default printer by name, since we already have that
* initialised.
*/
PrinterName defName = defService.getAttribute(PrinterName.class);
if (defName != null && name.equals(defName)) {
if (matchesAttributes(defService, serviceSet)) {
services = new PrintService[1];
services[0] = defService;
return services;
} else {
return new PrintService[0];
}
} else {
/* Its not the default service */
PrintService service = getServiceByName(name);
if (service != null &&
matchesAttributes(service, serviceSet)) {
services = new PrintService[1];
services[0] = service;
return services;
} else {
return new PrintService[0];
}
}
} else {
/* specified service attributes don't include a name.*/
Vector<PrintService> matchedServices = new Vector<>();
services = getPrintServices();
for (int i = 0; i< services.length; i++) {
if (matchesAttributes(services[i], serviceSet)) {
matchedServices.add(services[i]);
}
}
services = new PrintService[matchedServices.size()];
for (int i = 0; i< services.length; i++) {
services[i] = matchedServices.elementAt(i);
}
return services;
}
}
/*
* If service attributes are specified then there must be additional
* filtering.
*/
public PrintService[] getPrintServices(DocFlavor flavor,
AttributeSet attributes) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPrintJobAccess();
}
PrintRequestAttributeSet requestSet = null;
PrintServiceAttributeSet serviceSet = null;
if (attributes != null && !attributes.isEmpty()) {
requestSet = new HashPrintRequestAttributeSet();
serviceSet = new HashPrintServiceAttributeSet();
Attribute[] attrs = attributes.toArray();
for (int i=0; i<attrs.length; i++) {
if (attrs[i] instanceof PrintRequestAttribute) {
requestSet.add(attrs[i]);
} else if (attrs[i] instanceof PrintServiceAttribute) {
serviceSet.add(attrs[i]);
}
}
}
PrintService[] services = getPrintServices(serviceSet);
if (services.length == 0) {
return services;
}
if (CUPSPrinter.isCupsRunning()) {
ArrayList<PrintService> matchingServices = new ArrayList<>();
for (int i=0; i<services.length; i++) {
try {
if (services[i].
getUnsupportedAttributes(flavor, requestSet) == null) {
matchingServices.add(services[i]);
}
} catch (IllegalArgumentException e) {
}
}
services = new PrintService[matchingServices.size()];
return matchingServices.toArray(services);
} else {
// We only need to compare 1 PrintService because all
// UnixPrintServices are the same anyway. We will not use
// default PrintService because it might be null.
PrintService service = services[0];
if ((flavor == null ||
service.isDocFlavorSupported(flavor)) &&
service.getUnsupportedAttributes(flavor, requestSet) == null)
{
return services;
} else {
return new PrintService[0];
}
}
}
/*
* return empty array as don't support multi docs
*/
public MultiDocPrintService[]
getMultiDocPrintServices(DocFlavor[] flavors,
AttributeSet attributes) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPrintJobAccess();
}
return new MultiDocPrintService[0];
}
public synchronized PrintService getDefaultPrintService() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPrintJobAccess();
}
// clear defaultPrintService
defaultPrintService = null;
String psuri = null;
IPPPrintService.debug_println("isRunning ? "+
(CUPSPrinter.isCupsRunning()));
if (CUPSPrinter.isCupsRunning()) {
String[] printerInfo = CUPSPrinter.getDefaultPrinter();
if (printerInfo != null && printerInfo.length >= 2) {
defaultPrinter = printerInfo[0];
psuri = printerInfo[1];
}
} else {
if (isMac() || isSysV()) {
defaultPrinter = getDefaultPrinterNameSysV();
} else if (isAIX()) {
defaultPrinter = getDefaultPrinterNameAIX();
} else {
defaultPrinter = getDefaultPrinterNameBSD();
}
}
if (defaultPrinter == null) {
return null;
}
defaultPrintService = null;
if (printServices != null) {
for (int j=0; j<printServices.length; j++) {
if (defaultPrinter.equals(getPrinterDestName(printServices[j]))) {
defaultPrintService = printServices[j];
break;
}
}
}
if (defaultPrintService == null) {
if (CUPSPrinter.isCupsRunning()) {
try {
PrintService defaultPS;
if ((psuri != null) && !psuri.startsWith("file")) {
defaultPS = new IPPPrintService(defaultPrinter,
psuri, true);
} else {
defaultPS = new IPPPrintService(defaultPrinter,
new URL("http://"+
CUPSPrinter.getServer()+":"+
CUPSPrinter.getPort()+"/"+
defaultPrinter));
}
defaultPrintService = defaultPS;
} catch (Exception e) {
}
} else {
defaultPrintService = new UnixPrintService(defaultPrinter);
}
}
return defaultPrintService;
}
public synchronized void
getServicesInbackground(BackgroundLookupListener listener) {
if (printServices != null) {
listener.notifyServices(printServices);
} else {
if (lookupListeners == null) {
lookupListeners = new Vector<>();
lookupListeners.add(listener);
Thread lookupThread = new Thread(this);
lookupThread.start();
} else {
lookupListeners.add(listener);
}
}
}
/* This method isn't used in most cases because we rely on code in
* javax.print.PrintServiceLookup. This is needed just for the cases
* where those interfaces are by-passed.
*/
private PrintService[] copyOf(PrintService[] inArr) {
if (inArr == null || inArr.length == 0) {
return inArr;
} else {
PrintService []outArr = new PrintService[inArr.length];
System.arraycopy(inArr, 0, outArr, 0, inArr.length);
return outArr;
}
}
public void run() {
PrintService[] services = getPrintServices();
synchronized (this) {
BackgroundLookupListener listener;
for (int i=0; i<lookupListeners.size(); i++) {
listener = lookupListeners.elementAt(i);
listener.notifyServices(copyOf(services));
}
lookupListeners = null;
}
}
private String getDefaultPrinterNameBSD() {
if (cmdIndex == UNINITIALIZED) {
cmdIndex = getBSDCommandIndex();
}
String[] names = execCmd(lpcFirstCom[cmdIndex]);
if (names == null || names.length == 0) {
return null;
}
if ((cmdIndex==BSD_LPD_NG) &&
(names[0].startsWith("missingprinter"))) {
return null;
}
return names[0];
}
private PrintService getNamedPrinterNameBSD(String name) {
if (cmdIndex == UNINITIALIZED) {
cmdIndex = getBSDCommandIndex();
}
String command = "/usr/sbin/lpc status " + name + lpcNameCom[cmdIndex];
String[] result = execCmd(command);
if (result == null || !(result[0].equals(name))) {
return null;
}
return new UnixPrintService(name);
}
private String[] getAllPrinterNamesBSD() {
if (cmdIndex == UNINITIALIZED) {
cmdIndex = getBSDCommandIndex();
}
String[] names = execCmd(lpcAllCom[cmdIndex]);
if (names == null || names.length == 0) {
return null;
}
return names;
}
static String getDefaultPrinterNameSysV() {
String defaultPrinter = "lp";
String command = "/usr/bin/lpstat -d";
String [] names = execCmd(command);
if (names == null || names.length == 0) {
return defaultPrinter;
} else {
int index = names[0].indexOf(":");
if (index == -1 || (names[0].length() <= index+1)) {
return null;
} else {
String name = names[0].substring(index+1).trim();
if (name.length() == 0) {
return null;
} else {
return name;
}
}
}
}
private PrintService getNamedPrinterNameSysV(String name) {
String command = "/usr/bin/lpstat -v " + name;
String []result = execCmd(command);
if (result == null || result[0].indexOf("unknown printer") > 0) {
return null;
} else {
return new UnixPrintService(name);
}
}
private String[] getAllPrinterNamesSysV() {
String defaultPrinter = "lp";
String command = "/usr/bin/lpstat -v|/usr/bin/expand|/usr/bin/cut -f3 -d' ' |/usr/bin/cut -f1 -d':' | /usr/bin/sort";
String [] names = execCmd(command);
ArrayList<String> printerNames = new ArrayList<>();
for (int i=0; i < names.length; i++) {
if (!names[i].equals("_default") &&
!names[i].equals(defaultPrinter) &&
!names[i].isEmpty()) {
printerNames.add(names[i]);
}
}
return printerNames.toArray(new String[printerNames.size()]);
}
private String getDefaultPrinterNameAIX() {
String[] names = execCmd(lpNameComAix[aix_lpstat_d]);
// Remove headers and bogus entries added by remote printers.
names = UnixPrintService.filterPrinterNamesAIX(names);
if (names == null || names.length != 1) {
// No default printer found
return null;
} else {
return names[0];
}
}
private PrintService getNamedPrinterNameAIX(String name) {
// On AIX there should be no blank after '-v'.
String[] result = execCmd(lpNameComAix[aix_lpstat_v] + name);
// Remove headers and bogus entries added by remote printers.
result = UnixPrintService.filterPrinterNamesAIX(result);
if (result == null || result.length != 1) {
return null;
} else {
return new UnixPrintService(name);
}
}
private String[] getAllPrinterNamesAIX() {
// Determine all printers of the system.
String [] names = execCmd(lpNameComAix[aix_defaultPrinterEnumeration]);
// Remove headers and bogus entries added by remote printers.
names = UnixPrintService.filterPrinterNamesAIX(names);
ArrayList<String> printerNames = new ArrayList<String>();
for ( int i=0; i < names.length; i++) {
printerNames.add(names[i]);
}
return printerNames.toArray(new String[printerNames.size()]);
}
/**代码未完, 请加载全部代码(NowJava.com).**/