/* * Copyright (c) 2003, 2018, 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.net.URL; import java.net.HttpURLConnection; import java.io.OutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import sun.print.IPPPrintService; import sun.print.CustomMediaSizeName; import sun.print.CustomMediaTray; import javax.print.attribute.standard.Media; import javax.print.attribute.standard.MediaSizeName; import javax.print.attribute.standard.MediaSize; import javax.print.attribute.standard.MediaTray; import javax.print.attribute.standard.MediaPrintableArea; import javax.print.attribute.standard.PrinterResolution; import javax.print.attribute.Size2DSyntax; import javax.print.attribute.Attribute; import javax.print.attribute.EnumSyntax; import javax.print.attribute.standard.PrinterName; public class CUPSPrinter { private static final String debugPrefix = "CUPSPrinter>> "; private static final double PRINTER_DPI = 72.0; private boolean initialized; private static native String getCupsServer(); private static native int getCupsPort(); private static native String getCupsDefaultPrinter(); private static native boolean canConnect(String server, int port); private static native boolean initIDs(); // These functions need to be synchronized as // CUPS does not support multi-threading. private static synchronized native String[] getMedia(String printer); private static synchronized native float[] getPageSizes(String printer); private static synchronized native void getResolutions(String printer, ArrayList resolutionList); //public static boolean useIPPMedia = false; will be used later private MediaPrintableArea[] cupsMediaPrintables; private MediaSizeName[] cupsMediaSNames; private CustomMediaSizeName[] cupsCustomMediaSNames; private MediaTray[] cupsMediaTrays; public int nPageSizes = 0; public int nTrays = 0; private String[] media; private float[] pageSizes; int[] resolutionsArray; private String printer; private static boolean libFound; private static String cupsServer = null; private static int cupsPort = 0; static { // load awt library to access native code java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { System.loadLibrary("awt"); return null; } }); libFound = initIDs(); if (libFound) { cupsServer = getCupsServer(); cupsPort = getCupsPort(); } } CUPSPrinter (String printerName) { if (printerName == null) { throw new IllegalArgumentException("null printer name"); } printer = printerName; cupsMediaSNames = null; cupsMediaPrintables = null; cupsMediaTrays = null; initialized = false; if (!libFound) { throw new RuntimeException("cups lib not found"); } else { // get page + tray names media = getMedia(printer); if (media == null) { // either PPD file is not found or printer is unknown throw new RuntimeException("error getting PPD"); } // get sizes pageSizes = getPageSizes(printer); if (pageSizes != null) { nPageSizes = pageSizes.length/6; nTrays = media.length/2-nPageSizes; assert (nTrays >= 0); } ArrayList resolutionList = new ArrayList<>(); getResolutions(printer, resolutionList); resolutionsArray = new int[resolutionList.size()]; for (int i=0; i < resolutionList.size(); i++) { resolutionsArray[i] = resolutionList.get(i); } } } /** * Returns array of MediaSizeNames derived from PPD. */ MediaSizeName[] getMediaSizeNames() { initMedia(); return cupsMediaSNames; } /** * Returns array of Custom MediaSizeNames derived from PPD. */ CustomMediaSizeName[] getCustomMediaSizeNames() { initMedia(); return cupsCustomMediaSNames; } public int getDefaultMediaIndex() { return ((pageSizes.length >1) ? (int)(pageSizes[pageSizes.length -1]) : 0); } /** * Returns array of MediaPrintableArea derived from PPD. */ MediaPrintableArea[] getMediaPrintableArea() { initMedia(); return cupsMediaPrintables; } /** * Returns array of MediaTrays derived from PPD. */ MediaTray[] getMediaTrays() { initMedia(); return cupsMediaTrays; } /** * return the raw packed array of supported printer resolutions. */ int[] getRawResolutions() { return resolutionsArray; } /** * Initialize media by translating PPD info to PrintService attributes. */ private synchronized void initMedia() { if (initialized) { return; } else { initialized = true; } if (pageSizes == null) { return; } cupsMediaPrintables = new MediaPrintableArea[nPageSizes]; cupsMediaSNames = new MediaSizeName[nPageSizes]; cupsCustomMediaSNames = new CustomMediaSizeName[nPageSizes]; CustomMediaSizeName msn; MediaPrintableArea mpa; float length, width, x, y, w, h; // initialize names and printables for (int i=0; i 0.0) && (length > 0.0)) { try { new MediaSize(width, length, Size2DSyntax.INCH, msn); } catch (IllegalArgumentException e) { /* PDF printer in Linux for Ledger paper causes "IllegalArgumentException: X dimension > Y dimension". We rotate based on IPP spec. */ new MediaSize(length, width, Size2DSyntax.INCH, msn); } } } // add to list of custom MediaSizeName // for internal use of IPPPrintService cupsCustomMediaSNames[i] = msn; mpa = null; try { mpa = new MediaPrintableArea(x, y, w, h, MediaPrintableArea.INCH); } catch (IllegalArgumentException e) { if (width > 0 && length > 0) { mpa = new MediaPrintableArea(0, 0, width, length, MediaPrintableArea.INCH); } } cupsMediaPrintables[i] = mpa; } // initialize trays cupsMediaTrays = new MediaTray[nTrays]; MediaTray mt; for (int i=0; i() { public OutputStream run() { try { return urlConnection.getOutputStream(); } catch (Exception e) { IPPPrintService.debug_println(debugPrefix+e); } return null; } }); if (os == null) { return null; } AttributeClass[] attCl = { AttributeClass.ATTRIBUTES_CHARSET, AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE, new AttributeClass("requested-attributes", AttributeClass.TAG_URI, "printer-uri") }; if (IPPPrintService.writeIPPRequest(os, IPPPrintService.OP_CUPS_GET_DEFAULT, attCl)) { HashMap defaultMap = null; InputStream is = urlConnection.getInputStream(); HashMap[] responseMap = IPPPrintService.readIPPResponse( is); is.close(); if (responseMap != null && responseMap.length > 0) { defaultMap = responseMap[0]; } else { IPPPrintService.debug_println(debugPrefix+ " empty response map for GET_DEFAULT."); } if (defaultMap == null) { os.close(); urlConnection.disconnect(); /* CUPS on OS X, as initially configured, considers the * default printer to be the last one used that's * presently available. So if no default was * reported, exec lpstat -d which has all the Apple * special behaviour for this built in. */ if (PrintServiceLookupProvider.isMac()) { printerInfo[0] = PrintServiceLookupProvider. getDefaultPrinterNameSysV(); printerInfo[1] = null; return printerInfo.clone(); } else { return null; } } AttributeClass attribClass = defaultMap.get("printer-name"); if (attribClass != null) { printerInfo[0] = attribClass.getStringValue(); attribClass = defaultMap.get("printer-uri-supported"); IPPPrintService.debug_println(debugPrefix+ "printer-uri-supported="+attribClass); if (attribClass != null) { printerInfo[1] = attribClass.getStringValue(); } else { printerInfo[1] = null; } os.close(); urlConnection.disconnect(); return printerInfo.clone(); } } os.close(); urlConnection.disconnect(); } } catch (Exception e) { } return null; } /** * Get list of all CUPS printers using IPP. */ static String[] getAllPrinters() { try { URL url = new URL("http", getServer(), getPort(), ""); final HttpURLConnection urlConnection = IPPPrintService.getIPPConnection(url); if (urlConnection != null) { OutputStream os = java.security.AccessController. doPrivileged(new java.security.PrivilegedAction() { public OutputStream run() { try { return urlConnection.getOutputStream(); } catch (Exception e) { } return null; } }); if (os == null) { return null; } AttributeClass[] attCl = { AttributeClass.ATTRIBUTES_CHARSET, AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE, new AttributeClass("requested-attributes", AttributeClass.TAG_KEYWORD, "printer-uri-supported") }; if (IPPPrintService.writeIPPRequest(os, IPPPrintService.OP_CUPS_GET_PRINTERS, attCl)) { InputStream is = urlConnection.getInputStream(); HashMap[] responseMap = IPPPrintService.readIPPResponse(is); is.close(); os.close(); urlConnection.disconnect(); if (responseMap == null || responseMap.length == 0) { return null; } ArrayList printerNames = new ArrayList<>(); for (int i=0; i< responseMap.length; i++) { AttributeClass attribClass = responseMap[i].get("printer-uri-supported"); if (attribClass != null) { String nameStr = attribClass.getStringValue(); printerNames.add(nameStr); } } return printerNames.toArray(new String[] {}); } else { os.close(); urlConnection.disconnect(); } } } catch (Exception e) { } return null; } /** * Returns CUPS server name. */ public static String getServer() { return cupsServer; } /** * Returns CUPS port number. */ public static int getPort() { return cupsPort; } /** * Detects if CUPS is running. */ public static boolean isCupsRunning() { IPPPrintService.debug_println(debugPrefix+"libFound "+libFound); if (libFound) { IPPPrintService.debug_println(debugPrefix+"CUPS server "+getServer()+ " port "+getPort()); return canConnect(getServer(), getPort()); } else { return false; } } }