Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/print/IPPPrintService.java
32287 views
/*1* Copyright (c) 2003, 2013, 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 javax.print.attribute.*;28import javax.print.attribute.standard.*;29import javax.print.DocFlavor;30import javax.print.DocPrintJob;31import javax.print.PrintService;32import javax.print.ServiceUIFactory;33import java.util.ArrayList;34import java.util.HashMap;35import java.util.Locale;36import java.util.Date;37import java.util.Arrays;38import java.security.AccessController;39import java.security.PrivilegedActionException;40import java.security.PrivilegedExceptionAction;41import javax.print.event.PrintServiceAttributeListener;4243import java.net.URI;44import java.net.URISyntaxException;45import java.net.URL;46import java.net.URLConnection;47import java.net.HttpURLConnection;48import java.io.File;49import java.io.InputStream;50import java.io.OutputStream;51import java.io.OutputStreamWriter;52import java.io.DataInputStream;53import java.io.ByteArrayOutputStream;54import java.io.ByteArrayInputStream;55import java.io.BufferedReader;56import java.io.InputStreamReader;57import java.nio.charset.Charset;5859import java.util.Iterator;60import java.util.HashSet;61import java.util.Map;62import java.util.Set;6364public class IPPPrintService implements PrintService, SunPrinterJobService {6566public static final boolean debugPrint;67private static final String debugPrefix = "IPPPrintService>> ";68protected static void debug_println(String str) {69if (debugPrint) {70System.out.println(str);71}72}7374private static final String FORCE_PIPE_PROP = "sun.print.ippdebug";7576static {77String debugStr =78(String)java.security.AccessController.doPrivileged(79new sun.security.action.GetPropertyAction(FORCE_PIPE_PROP));8081debugPrint = "true".equalsIgnoreCase(debugStr);82}8384private String printer;85private URI myURI;86private URL myURL;87transient private ServiceNotifier notifier = null;8889private static int MAXCOPIES = 1000;90private static short MAX_ATTRIBUTE_LENGTH = 255;9192private CUPSPrinter cps;93private HttpURLConnection urlConnection = null;94private DocFlavor[] supportedDocFlavors;95private Class[] supportedCats;96private MediaTray[] mediaTrays;97private MediaSizeName[] mediaSizeNames;98private CustomMediaSizeName[] customMediaSizeNames;99private int defaultMediaIndex;100private boolean isCupsPrinter;101private boolean init;102private Boolean isPS;103private HashMap getAttMap;104private boolean pngImagesAdded = false;105private boolean gifImagesAdded = false;106private boolean jpgImagesAdded = false;107108109/**110* IPP Status Codes111*/112private static final byte STATUSCODE_SUCCESS = 0x00;113114/**115* IPP Group Tags. Each tag is used once before the first attribute116* of that group.117*/118// operation attributes group119private static final byte GRPTAG_OP_ATTRIBUTES = 0x01;120// job attributes group121private static final byte GRPTAG_JOB_ATTRIBUTES = 0x02;122// printer attributes group123private static final byte GRPTAG_PRINTER_ATTRIBUTES = 0x04;124// used as the last tag in an IPP message.125private static final byte GRPTAG_END_ATTRIBUTES = 0x03;126127/**128* IPP Operation codes129*/130// gets the attributes for a printer131public static final String OP_GET_ATTRIBUTES = "000B";132// gets the default printer133public static final String OP_CUPS_GET_DEFAULT = "4001";134// gets the list of printers135public static final String OP_CUPS_GET_PRINTERS = "4002";136137138/**139* List of all PrintRequestAttributes. This is used140* for looping through all the IPP attribute name.141*/142private static Object[] printReqAttribDefault = {143Chromaticity.COLOR,144new Copies(1),145Fidelity.FIDELITY_FALSE,146Finishings.NONE,147//new JobHoldUntil(new Date()),148//new JobImpressions(0),149//JobImpressions,150//JobKOctets,151//JobMediaSheets,152new JobName("", Locale.getDefault()),153//JobPriority,154JobSheets.NONE,155(Media)MediaSizeName.NA_LETTER,156//MediaPrintableArea.class, // not an IPP attribute157//MultipleDocumentHandling.SINGLE_DOCUMENT,158new NumberUp(1),159OrientationRequested.PORTRAIT,160new PageRanges(1),161//PresentationDirection,162// CUPS does not supply printer-resolution attribute163//new PrinterResolution(300, 300, PrinterResolution.DPI),164//PrintQuality.NORMAL,165new RequestingUserName("", Locale.getDefault()),166//SheetCollate.UNCOLLATED, //CUPS has no sheet collate?167Sides.ONE_SIDED,168};169170171/**172* List of all PrintServiceAttributes. This is used173* for looping through all the IPP attribute name.174*/175private static Object[][] serviceAttributes = {176{ColorSupported.class, "color-supported"},177{PagesPerMinute.class, "pages-per-minute"},178{PagesPerMinuteColor.class, "pages-per-minute-color"},179{PDLOverrideSupported.class, "pdl-override-supported"},180{PrinterInfo.class, "printer-info"},181{PrinterIsAcceptingJobs.class, "printer-is-accepting-jobs"},182{PrinterLocation.class, "printer-location"},183{PrinterMakeAndModel.class, "printer-make-and-model"},184{PrinterMessageFromOperator.class, "printer-message-from-operator"},185{PrinterMoreInfo.class, "printer-more-info"},186{PrinterMoreInfoManufacturer.class, "printer-more-info-manufacturer"},187{PrinterName.class, "printer-name"},188{PrinterState.class, "printer-state"},189{PrinterStateReasons.class, "printer-state-reasons"},190{PrinterURI.class, "printer-uri"},191{QueuedJobCount.class, "queued-job-count"}192};193194195/**196* List of DocFlavors, grouped based on matching mime-type.197* NOTE: For any change in the predefined DocFlavors, it must be reflected198* here also.199*/200// PDF DocFlavors201private static DocFlavor[] appPDF = {202DocFlavor.BYTE_ARRAY.PDF,203DocFlavor.INPUT_STREAM.PDF,204DocFlavor.URL.PDF205};206207// Postscript DocFlavors208private static DocFlavor[] appPostScript = {209DocFlavor.BYTE_ARRAY.POSTSCRIPT,210DocFlavor.INPUT_STREAM.POSTSCRIPT,211DocFlavor.URL.POSTSCRIPT212};213214// Autosense DocFlavors215private static DocFlavor[] appOctetStream = {216DocFlavor.BYTE_ARRAY.AUTOSENSE,217DocFlavor.INPUT_STREAM.AUTOSENSE,218DocFlavor.URL.AUTOSENSE219};220221// Text DocFlavors222private static DocFlavor[] textPlain = {223DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_8,224DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16,225DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16BE,226DocFlavor.BYTE_ARRAY.TEXT_PLAIN_UTF_16LE,227DocFlavor.BYTE_ARRAY.TEXT_PLAIN_US_ASCII,228DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_8,229DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16,230DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16BE,231DocFlavor.INPUT_STREAM.TEXT_PLAIN_UTF_16LE,232DocFlavor.INPUT_STREAM.TEXT_PLAIN_US_ASCII,233DocFlavor.URL.TEXT_PLAIN_UTF_8,234DocFlavor.URL.TEXT_PLAIN_UTF_16,235DocFlavor.URL.TEXT_PLAIN_UTF_16BE,236DocFlavor.URL.TEXT_PLAIN_UTF_16LE,237DocFlavor.URL.TEXT_PLAIN_US_ASCII,238DocFlavor.CHAR_ARRAY.TEXT_PLAIN,239DocFlavor.STRING.TEXT_PLAIN,240DocFlavor.READER.TEXT_PLAIN241};242243private static DocFlavor[] textPlainHost = {244DocFlavor.BYTE_ARRAY.TEXT_PLAIN_HOST,245DocFlavor.INPUT_STREAM.TEXT_PLAIN_HOST,246DocFlavor.URL.TEXT_PLAIN_HOST247};248249// JPG DocFlavors250private static DocFlavor[] imageJPG = {251DocFlavor.BYTE_ARRAY.JPEG,252DocFlavor.INPUT_STREAM.JPEG,253DocFlavor.URL.JPEG254};255256// GIF DocFlavors257private static DocFlavor[] imageGIF = {258DocFlavor.BYTE_ARRAY.GIF,259DocFlavor.INPUT_STREAM.GIF,260DocFlavor.URL.GIF261};262263// PNG DocFlavors264private static DocFlavor[] imagePNG = {265DocFlavor.BYTE_ARRAY.PNG,266DocFlavor.INPUT_STREAM.PNG,267DocFlavor.URL.PNG268};269270// HTML DocFlavors271private static DocFlavor[] textHtml = {272DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_8,273DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16,274DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16BE,275DocFlavor.BYTE_ARRAY.TEXT_HTML_UTF_16LE,276DocFlavor.BYTE_ARRAY.TEXT_HTML_US_ASCII,277DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_8,278DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16,279DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16BE,280DocFlavor.INPUT_STREAM.TEXT_HTML_UTF_16LE,281DocFlavor.INPUT_STREAM.TEXT_HTML_US_ASCII,282DocFlavor.URL.TEXT_HTML_UTF_8,283DocFlavor.URL.TEXT_HTML_UTF_16,284DocFlavor.URL.TEXT_HTML_UTF_16BE,285DocFlavor.URL.TEXT_HTML_UTF_16LE,286DocFlavor.URL.TEXT_HTML_US_ASCII,287// These are not handled in UnixPrintJob so commenting these288// for now.289/*290DocFlavor.CHAR_ARRAY.TEXT_HTML,291DocFlavor.STRING.TEXT_HTML,292DocFlavor.READER.TEXT_HTML,293*/294};295296private static DocFlavor[] textHtmlHost = {297DocFlavor.BYTE_ARRAY.TEXT_HTML_HOST,298DocFlavor.INPUT_STREAM.TEXT_HTML_HOST,299DocFlavor.URL.TEXT_HTML_HOST,300};301302303// PCL DocFlavors304private static DocFlavor[] appPCL = {305DocFlavor.BYTE_ARRAY.PCL,306DocFlavor.INPUT_STREAM.PCL,307DocFlavor.URL.PCL308};309310// List of all DocFlavors, used in looping311// through all supported mime-types312private static Object[] allDocFlavors = {313appPDF, appPostScript, appOctetStream,314textPlain, imageJPG, imageGIF, imagePNG,315textHtml, appPCL,316};317318319IPPPrintService(String name, URL url) {320if ((name == null) || (url == null)){321throw new IllegalArgumentException("null uri or printer name");322}323printer = name;324supportedDocFlavors = null;325supportedCats = null;326mediaSizeNames = null;327customMediaSizeNames = null;328mediaTrays = null;329myURL = url;330cps = null;331isCupsPrinter = false;332init = false;333defaultMediaIndex = -1;334335String host = myURL.getHost();336if (host!=null && host.equals(CUPSPrinter.getServer())) {337isCupsPrinter = true;338try {339myURI = new URI("ipp://"+host+340"/printers/"+printer);341debug_println(debugPrefix+"IPPPrintService myURI : "+myURI);342} catch (java.net.URISyntaxException e) {343throw new IllegalArgumentException("invalid url");344}345}346}347348349IPPPrintService(String name, String uriStr, boolean isCups) {350if ((name == null) || (uriStr == null)){351throw new IllegalArgumentException("null uri or printer name");352}353printer = name;354supportedDocFlavors = null;355supportedCats = null;356mediaSizeNames = null;357customMediaSizeNames = null;358mediaTrays = null;359cps = null;360init = false;361defaultMediaIndex = -1;362try {363myURL =364new URL(uriStr.replaceFirst("ipp", "http"));365} catch (Exception e) {366IPPPrintService.debug_println(debugPrefix+367" IPPPrintService, myURL="+368myURL+" Exception= "+369e);370throw new IllegalArgumentException("invalid url");371}372373isCupsPrinter = isCups;374try {375myURI = new URI(uriStr);376debug_println(debugPrefix+"IPPPrintService myURI : "+myURI);377} catch (java.net.URISyntaxException e) {378throw new IllegalArgumentException("invalid uri");379}380}381382383/*384* Initialize mediaSizeNames, mediaTrays and other attributes.385* Media size/trays are initialized to non-null values, may be 0-length386* array.387* NOTE: Must be called from a synchronized block only.388*/389private void initAttributes() {390if (!init) {391// init customMediaSizeNames392customMediaSizeNames = new CustomMediaSizeName[0];393394if ((urlConnection = getIPPConnection(myURL)) == null) {395mediaSizeNames = new MediaSizeName[0];396mediaTrays = new MediaTray[0];397debug_println(debugPrefix+"initAttributes, NULL urlConnection ");398init = true;399return;400}401402// get all supported attributes through IPP403opGetAttributes();404405if (isCupsPrinter) {406// note, it is possible to query media in CUPS using IPP407// right now we always get it from PPD.408// maybe use "&& (usePPD)" later?409// Another reason why we use PPD is because410// IPP currently does not support it but PPD does.411412try {413cps = new CUPSPrinter(printer);414mediaSizeNames = cps.getMediaSizeNames();415mediaTrays = cps.getMediaTrays();416customMediaSizeNames = cps.getCustomMediaSizeNames();417defaultMediaIndex = cps.getDefaultMediaIndex();418urlConnection.disconnect();419init = true;420return;421} catch (Exception e) {422IPPPrintService.debug_println(debugPrefix+423"initAttributes, error creating CUPSPrinter e="+e);424}425}426427// use IPP to get all media,428Media[] allMedia = (Media[])getSupportedMedia();429ArrayList sizeList = new ArrayList();430ArrayList trayList = new ArrayList();431for (int i=0; i<allMedia.length; i++) {432if (allMedia[i] instanceof MediaSizeName) {433sizeList.add(allMedia[i]);434} else if (allMedia[i] instanceof MediaTray) {435trayList.add(allMedia[i]);436}437}438439if (sizeList != null) {440mediaSizeNames = new MediaSizeName[sizeList.size()];441mediaSizeNames = (MediaSizeName[])sizeList.toArray(442mediaSizeNames);443}444if (trayList != null) {445mediaTrays = new MediaTray[trayList.size()];446mediaTrays = (MediaTray[])trayList.toArray(447mediaTrays);448}449urlConnection.disconnect();450451init = true;452}453}454455456public DocPrintJob createPrintJob() {457SecurityManager security = System.getSecurityManager();458if (security != null) {459security.checkPrintJobAccess();460}461// REMIND: create IPPPrintJob462return new UnixPrintJob(this);463}464465466public synchronized Object467getSupportedAttributeValues(Class<? extends Attribute> category,468DocFlavor flavor,469AttributeSet attributes)470{471if (category == null) {472throw new NullPointerException("null category");473}474if (!Attribute.class.isAssignableFrom(category)) {475throw new IllegalArgumentException(category +476" does not implement Attribute");477}478if (flavor != null) {479if (!isDocFlavorSupported(flavor)) {480throw new IllegalArgumentException(flavor +481" is an unsupported flavor");482} else if (isAutoSense(flavor)) {483return null;484}485486}487488if (!isAttributeCategorySupported(category)) {489return null;490}491492/* Test if the flavor is compatible with the attributes */493if (!isDestinationSupported(flavor, attributes)) {494return null;495}496497initAttributes();498499/* Test if the flavor is compatible with the category */500if ((category == Copies.class) ||501(category == CopiesSupported.class)) {502if (flavor == null ||503!(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||504flavor.equals(DocFlavor.URL.POSTSCRIPT) ||505flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) {506CopiesSupported cs = new CopiesSupported(1, MAXCOPIES);507AttributeClass attribClass = (getAttMap != null) ?508(AttributeClass)getAttMap.get(cs.getName()) : null;509if (attribClass != null) {510int[] range = attribClass.getIntRangeValue();511cs = new CopiesSupported(range[0], range[1]);512}513return cs;514} else {515return null;516}517} else if (category == Chromaticity.class) {518if (flavor == null ||519flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||520flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||521!isIPPSupportedImages(flavor.getMimeType())) {522Chromaticity[]arr = new Chromaticity[1];523arr[0] = Chromaticity.COLOR;524return (arr);525} else {526return null;527}528} else if (category == Destination.class) {529if (flavor == null ||530flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||531flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {532try {533return new Destination((new File("out.ps")).toURI());534} catch (SecurityException se) {535try {536return new Destination(new URI("file:out.ps"));537} catch (URISyntaxException e) {538return null;539}540}541}542return null;543} else if (category == Fidelity.class) {544Fidelity []arr = new Fidelity[2];545arr[0] = Fidelity.FIDELITY_FALSE;546arr[1] = Fidelity.FIDELITY_TRUE;547return arr;548} else if (category == Finishings.class) {549AttributeClass attribClass = (getAttMap != null) ?550(AttributeClass)getAttMap.get("finishings-supported")551: null;552if (attribClass != null) {553int[] finArray = attribClass.getArrayOfIntValues();554if ((finArray != null) && (finArray.length > 0)) {555Finishings[] finSup = new Finishings[finArray.length];556for (int i=0; i<finArray.length; i++) {557finSup[i] = Finishings.NONE;558Finishings[] fAll = (Finishings[])559(new ExtFinishing(100)).getAll();560for (int j=0; j<fAll.length; j++) {561if (finArray[i] == fAll[j].getValue()) {562finSup[i] = fAll[j];563break;564}565}566}567return finSup;568}569}570} else if (category == JobName.class) {571return new JobName("Java Printing", null);572} else if (category == JobSheets.class) {573JobSheets arr[] = new JobSheets[2];574arr[0] = JobSheets.NONE;575arr[1] = JobSheets.STANDARD;576return arr;577578} else if (category == Media.class) {579Media[] allMedia = new Media[mediaSizeNames.length+580mediaTrays.length];581582for (int i=0; i<mediaSizeNames.length; i++) {583allMedia[i] = mediaSizeNames[i];584}585586for (int i=0; i<mediaTrays.length; i++) {587allMedia[i+mediaSizeNames.length] = mediaTrays[i];588}589590if (allMedia.length == 0) {591allMedia = new Media[1];592allMedia[0] = (Media)getDefaultAttributeValue(Media.class);593}594595return allMedia;596} else if (category == MediaPrintableArea.class) {597MediaPrintableArea[] mpas = null;598if (cps != null) {599mpas = cps.getMediaPrintableArea();600}601602if (mpas == null) {603mpas = new MediaPrintableArea[1];604mpas[0] = (MediaPrintableArea)605getDefaultAttributeValue(MediaPrintableArea.class);606}607608if ((attributes == null) || (attributes.size() == 0)) {609ArrayList<MediaPrintableArea> printableList =610new ArrayList<MediaPrintableArea>();611612for (int i=0; i<mpas.length; i++) {613if (mpas[i] != null) {614printableList.add(mpas[i]);615}616}617if (printableList.size() > 0) {618mpas = new MediaPrintableArea[printableList.size()];619printableList.toArray(mpas);620}621return mpas;622}623624int match = -1;625Media media = (Media)attributes.get(Media.class);626if (media != null && media instanceof MediaSizeName) {627MediaSizeName msn = (MediaSizeName)media;628629// case when no supported mediasizenames are reported630// check given media against the default631if (mediaSizeNames.length == 0 &&632msn.equals(getDefaultAttributeValue(Media.class))) {633//default printable area is that of default mediasize634return mpas;635}636637for (int i=0; i<mediaSizeNames.length; i++) {638if (msn.equals(mediaSizeNames[i])) {639match = i;640}641}642}643644if (match == -1) {645return null;646} else {647MediaPrintableArea []arr = new MediaPrintableArea[1];648arr[0] = mpas[match];649return arr;650}651} else if (category == NumberUp.class) {652AttributeClass attribClass = (getAttMap != null) ?653(AttributeClass)getAttMap.get("number-up-supported") : null;654if (attribClass != null) {655int[] values = attribClass.getArrayOfIntValues();656if (values != null) {657NumberUp[] nUp = new NumberUp[values.length];658for (int i=0; i<values.length; i++) {659nUp[i] = new NumberUp(values[i]);660}661return nUp;662} else {663return null;664}665}666} else if (category == OrientationRequested.class) {667if ((flavor != null) &&668(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||669flavor.equals(DocFlavor.URL.POSTSCRIPT) ||670flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) {671return null;672}673674boolean revPort = false;675OrientationRequested[] orientSup = null;676677AttributeClass attribClass = (getAttMap != null) ?678(AttributeClass)getAttMap.get("orientation-requested-supported")679: null;680if (attribClass != null) {681int[] orientArray = attribClass.getArrayOfIntValues();682if ((orientArray != null) && (orientArray.length > 0)) {683orientSup =684new OrientationRequested[orientArray.length];685for (int i=0; i<orientArray.length; i++) {686switch (orientArray[i]) {687default:688case 3 :689orientSup[i] = OrientationRequested.PORTRAIT;690break;691case 4:692orientSup[i] = OrientationRequested.LANDSCAPE;693break;694case 5:695orientSup[i] =696OrientationRequested.REVERSE_LANDSCAPE;697break;698case 6:699orientSup[i] =700OrientationRequested.REVERSE_PORTRAIT;701revPort = true;702break;703}704}705}706}707if (flavor == null ||708flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||709flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {710711if (revPort && flavor == null) {712OrientationRequested []orSup = new OrientationRequested[4];713orSup[0] = OrientationRequested.PORTRAIT;714orSup[1] = OrientationRequested.LANDSCAPE;715orSup[2] = OrientationRequested.REVERSE_LANDSCAPE;716orSup[3] = OrientationRequested.REVERSE_PORTRAIT;717return orSup;718} else {719OrientationRequested []orSup = new OrientationRequested[3];720orSup[0] = OrientationRequested.PORTRAIT;721orSup[1] = OrientationRequested.LANDSCAPE;722orSup[2] = OrientationRequested.REVERSE_LANDSCAPE;723return orSup;724}725} else {726return orientSup;727}728} else if (category == PageRanges.class) {729if (flavor == null ||730flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||731flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {732PageRanges []arr = new PageRanges[1];733arr[0] = new PageRanges(1, Integer.MAX_VALUE);734return arr;735} else {736// Returning null as this is not yet supported in UnixPrintJob.737return null;738}739} else if (category == RequestingUserName.class) {740String userName = "";741try {742userName = System.getProperty("user.name", "");743} catch (SecurityException se) {744}745return new RequestingUserName(userName, null);746} else if (category == Sides.class) {747// The printer takes care of Sides so if short-edge748// is chosen in a job, the rotation is done by the printer.749// Orientation is rotated by emulation if pageable750// or printable so if the document is in Landscape, this may751// result in double rotation.752AttributeClass attribClass = (getAttMap != null) ?753(AttributeClass)getAttMap.get("sides-supported")754: null;755if (attribClass != null) {756String[] sidesArray = attribClass.getArrayOfStringValues();757if ((sidesArray != null) && (sidesArray.length > 0)) {758Sides[] sidesSup = new Sides[sidesArray.length];759for (int i=0; i<sidesArray.length; i++) {760if (sidesArray[i].endsWith("long-edge")) {761sidesSup[i] = Sides.TWO_SIDED_LONG_EDGE;762} else if (sidesArray[i].endsWith("short-edge")) {763sidesSup[i] = Sides.TWO_SIDED_SHORT_EDGE;764} else {765sidesSup[i] = Sides.ONE_SIDED;766}767}768return sidesSup;769}770}771}772773return null;774}775776//This class is for getting all pre-defined Finishings777private class ExtFinishing extends Finishings {778ExtFinishing(int value) {779super(100); // 100 to avoid any conflicts with predefined values.780}781782EnumSyntax[] getAll() {783EnumSyntax[] es = super.getEnumValueTable();784return es;785}786}787788789public AttributeSet getUnsupportedAttributes(DocFlavor flavor,790AttributeSet attributes) {791if (flavor != null && !isDocFlavorSupported(flavor)) {792throw new IllegalArgumentException("flavor " + flavor +793"is not supported");794}795796if (attributes == null) {797return null;798}799800Attribute attr;801AttributeSet unsupp = new HashAttributeSet();802Attribute []attrs = attributes.toArray();803for (int i=0; i<attrs.length; i++) {804try {805attr = attrs[i];806if (!isAttributeCategorySupported(attr.getCategory())) {807unsupp.add(attr);808} else if (!isAttributeValueSupported(attr, flavor,809attributes)) {810unsupp.add(attr);811}812} catch (ClassCastException e) {813}814}815if (unsupp.isEmpty()) {816return null;817} else {818return unsupp;819}820}821822823public synchronized DocFlavor[] getSupportedDocFlavors() {824825if (supportedDocFlavors != null) {826int len = supportedDocFlavors.length;827DocFlavor[] copyflavors = new DocFlavor[len];828System.arraycopy(supportedDocFlavors, 0, copyflavors, 0, len);829return copyflavors;830}831initAttributes();832833if ((getAttMap != null) &&834getAttMap.containsKey("document-format-supported")) {835836AttributeClass attribClass =837(AttributeClass)getAttMap.get("document-format-supported");838if (attribClass != null) {839String mimeType;840boolean psSupported = false;841String[] docFlavors = attribClass.getArrayOfStringValues();842DocFlavor[] flavors;843HashSet docList = new HashSet();844int j;845String hostEnc = DocFlavor.hostEncoding.846toLowerCase(Locale.ENGLISH);847boolean addHostEncoding = !hostEnc.equals("utf-8") &&848!hostEnc.equals("utf-16") && !hostEnc.equals("utf-16be") &&849!hostEnc.equals("utf-16le") && !hostEnc.equals("us-ascii");850851for (int i = 0; i < docFlavors.length; i++) {852for (j=0; j<allDocFlavors.length; j++) {853flavors = (DocFlavor[])allDocFlavors[j];854855mimeType = flavors[0].getMimeType();856if (mimeType.startsWith(docFlavors[i])) {857858docList.addAll(Arrays.asList(flavors));859860if (mimeType.equals("text/plain") &&861addHostEncoding) {862docList.add(Arrays.asList(textPlainHost));863} else if (mimeType.equals("text/html") &&864addHostEncoding) {865docList.add(Arrays.asList(textHtmlHost));866} else if (mimeType.equals("image/png")) {867pngImagesAdded = true;868} else if (mimeType.equals("image/gif")) {869gifImagesAdded = true;870} else if (mimeType.equals("image/jpeg")) {871jpgImagesAdded = true;872} else if (mimeType.indexOf("postscript") != -1) {873psSupported = true;874}875break;876}877}878879// Not added? Create new DocFlavors880if (j == allDocFlavors.length) {881// make new DocFlavors882docList.add(new DocFlavor.BYTE_ARRAY(docFlavors[i]));883docList.add(new DocFlavor.INPUT_STREAM(docFlavors[i]));884docList.add(new DocFlavor.URL(docFlavors[i]));885}886}887888// check if we need to add image DocFlavors889// and Pageable/Printable flavors890if (psSupported || isCupsPrinter) {891/*892Always add Pageable and Printable for CUPS893since it uses Filters to convert from Postscript894to device printer language.895*/896docList.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE);897docList.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE);898899docList.addAll(Arrays.asList(imageJPG));900docList.addAll(Arrays.asList(imagePNG));901docList.addAll(Arrays.asList(imageGIF));902}903supportedDocFlavors = new DocFlavor[docList.size()];904docList.toArray(supportedDocFlavors);905int len = supportedDocFlavors.length;906DocFlavor[] copyflavors = new DocFlavor[len];907System.arraycopy(supportedDocFlavors, 0, copyflavors, 0, len);908return copyflavors;909}910}911return null;912}913914915public boolean isDocFlavorSupported(DocFlavor flavor) {916if (supportedDocFlavors == null) {917getSupportedDocFlavors();918}919if (supportedDocFlavors != null) {920for (int f=0; f<supportedDocFlavors.length; f++) {921if (flavor.equals(supportedDocFlavors[f])) {922return true;923}924}925}926return false;927}928929930/**931* Finds matching CustomMediaSizeName of given media.932*/933public CustomMediaSizeName findCustomMedia(MediaSizeName media) {934if (customMediaSizeNames == null) {935return null;936}937for (int i=0; i< customMediaSizeNames.length; i++) {938CustomMediaSizeName custom =939(CustomMediaSizeName)customMediaSizeNames[i];940MediaSizeName msn = custom.getStandardMedia();941if (media.equals(msn)) {942return customMediaSizeNames[i];943}944}945return null;946}947948949/**950* Returns the matching standard Media using string comparison of names.951*/952private Media getIPPMedia(String mediaName) {953CustomMediaSizeName sampleSize = new CustomMediaSizeName("sample", "",9540, 0);955Media[] sizes = sampleSize.getSuperEnumTable();956for (int i=0; i<sizes.length; i++) {957if (mediaName.equals(""+sizes[i])) {958return sizes[i];959}960}961CustomMediaTray sampleTray = new CustomMediaTray("sample", "");962Media[] trays = sampleTray.getSuperEnumTable();963for (int i=0; i<trays.length; i++) {964if (mediaName.equals(""+trays[i])) {965return trays[i];966}967}968return null;969}970971private Media[] getSupportedMedia() {972if ((getAttMap != null) &&973getAttMap.containsKey("media-supported")) {974975AttributeClass attribClass =976(AttributeClass)getAttMap.get("media-supported");977978if (attribClass != null) {979String[] mediaVals = attribClass.getArrayOfStringValues();980Media msn;981Media[] mediaNames =982new Media[mediaVals.length];983for (int i=0; i<mediaVals.length; i++) {984msn = getIPPMedia(mediaVals[i]);985//REMIND: if null, create custom?986mediaNames[i] = msn;987}988return mediaNames;989}990}991return new Media[0];992}993994995public synchronized Class[] getSupportedAttributeCategories() {996if (supportedCats != null) {997Class<?> [] copyCats = new Class<?>[supportedCats.length];998System.arraycopy(supportedCats, 0, copyCats, 0, copyCats.length);999return copyCats;1000}10011002initAttributes();10031004ArrayList catList = new ArrayList();1005Class cl;10061007for (int i=0; i < printReqAttribDefault.length; i++) {1008PrintRequestAttribute pra =1009(PrintRequestAttribute)printReqAttribDefault[i];1010if (getAttMap != null &&1011getAttMap.containsKey(pra.getName()+"-supported")) {1012cl = pra.getCategory();1013catList.add(cl);1014}1015}10161017// Some IPP printers like lexc710 do not have list of supported media1018// but CUPS can get the media from PPD, so we still report as1019// supported category.1020if (isCupsPrinter) {1021if (!catList.contains(Media.class)) {1022catList.add(Media.class);1023}10241025// Always add MediaPrintable for cups,1026// because we can get it from PPD.1027catList.add(MediaPrintableArea.class);10281029// this is already supported in UnixPrintJob1030catList.add(Destination.class);10311032// It is unfortunate that CUPS doesn't provide a way to query1033// if printer supports collation but since most printers1034// now supports collation and that most OS has a way1035// of setting it, it is a safe assumption to just always1036// include SheetCollate as supported attribute.10371038/*1039In Linux, we use Postscript for rendering but Linux still1040has issues in propagating Postscript-embedded setpagedevice1041setting like collation. Therefore, we temporarily exclude1042Linux.1043*/1044if (!PrintServiceLookupProvider.isLinux()) {1045catList.add(SheetCollate.class);1046}1047}10481049// With the assumption that Chromaticity is equivalent to1050// ColorSupported.1051if (getAttMap != null && getAttMap.containsKey("color-supported")) {1052catList.add(Chromaticity.class);1053}1054supportedCats = new Class[catList.size()];1055catList.toArray(supportedCats);1056Class<?>[] copyCats = new Class<?>[supportedCats.length];1057System.arraycopy(supportedCats, 0, copyCats, 0, copyCats.length);1058return copyCats;1059}106010611062public boolean1063isAttributeCategorySupported(Class<? extends Attribute> category)1064{1065if (category == null) {1066throw new NullPointerException("null category");1067}1068if (!(Attribute.class.isAssignableFrom(category))) {1069throw new IllegalArgumentException(category +1070" is not an Attribute");1071}10721073if (supportedCats == null) {1074getSupportedAttributeCategories();1075}10761077// It is safe to assume that Orientation is always supported1078// and even if CUPS or an IPP device reports it as not,1079// our renderer can do portrait, landscape and1080// reverse landscape.1081if (category == OrientationRequested.class) {1082return true;1083}10841085for (int i=0;i<supportedCats.length;i++) {1086if (category == supportedCats[i]) {1087return true;1088}1089}10901091return false;1092}109310941095public synchronized <T extends PrintServiceAttribute>1096T getAttribute(Class<T> category)1097{1098if (category == null) {1099throw new NullPointerException("category");1100}1101if (!(PrintServiceAttribute.class.isAssignableFrom(category))) {1102throw new IllegalArgumentException("Not a PrintServiceAttribute");1103}11041105initAttributes();11061107if (category == PrinterName.class) {1108return (T)(new PrinterName(printer, null));1109} else if (category == PrinterInfo.class) {1110PrinterInfo pInfo = new PrinterInfo(printer, null);1111AttributeClass ac = (getAttMap != null) ?1112(AttributeClass)getAttMap.get(pInfo.getName())1113: null;1114if (ac != null) {1115return (T)(new PrinterInfo(ac.getStringValue(), null));1116}1117return (T)pInfo;1118} else if (category == QueuedJobCount.class) {1119QueuedJobCount qjc = new QueuedJobCount(0);1120AttributeClass ac = (getAttMap != null) ?1121(AttributeClass)getAttMap.get(qjc.getName())1122: null;1123if (ac != null) {1124qjc = new QueuedJobCount(ac.getIntValue());1125}1126return (T)qjc;1127} else if (category == PrinterIsAcceptingJobs.class) {1128PrinterIsAcceptingJobs accJob =1129PrinterIsAcceptingJobs.ACCEPTING_JOBS;1130AttributeClass ac = (getAttMap != null) ?1131(AttributeClass)getAttMap.get(accJob.getName())1132: null;1133if ((ac != null) && (ac.getByteValue() == 0)) {1134accJob = PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;1135}1136return (T)accJob;1137} else if (category == ColorSupported.class) {1138ColorSupported cs = ColorSupported.SUPPORTED;1139AttributeClass ac = (getAttMap != null) ?1140(AttributeClass)getAttMap.get(cs.getName())1141: null;1142if ((ac != null) && (ac.getByteValue() == 0)) {1143cs = ColorSupported.NOT_SUPPORTED;1144}1145return (T)cs;1146} else if (category == PDLOverrideSupported.class) {11471148if (isCupsPrinter) {1149// Documented: For CUPS this will always be false1150return (T)PDLOverrideSupported.NOT_ATTEMPTED;1151} else {1152// REMIND: check attribute values1153return (T)PDLOverrideSupported.NOT_ATTEMPTED;1154}1155} else if (category == PrinterURI.class) {1156return (T)(new PrinterURI(myURI));1157} else {1158return null;1159}1160}116111621163public synchronized PrintServiceAttributeSet getAttributes() {1164// update getAttMap by sending again get-attributes IPP request1165init = false;1166initAttributes();11671168HashPrintServiceAttributeSet attrs =1169new HashPrintServiceAttributeSet();11701171for (int i=0; i < serviceAttributes.length; i++) {1172String name = (String)serviceAttributes[i][1];1173if (getAttMap != null && getAttMap.containsKey(name)) {1174Class c = (Class)serviceAttributes[i][0];1175PrintServiceAttribute psa = getAttribute(c);1176if (psa != null) {1177attrs.add(psa);1178}1179}1180}1181return AttributeSetUtilities.unmodifiableView(attrs);1182}11831184public boolean isIPPSupportedImages(String mimeType) {1185if (supportedDocFlavors == null) {1186getSupportedDocFlavors();1187}11881189if (mimeType.equals("image/png") && pngImagesAdded) {1190return true;1191} else if (mimeType.equals("image/gif") && gifImagesAdded) {1192return true;1193} else if (mimeType.equals("image/jpeg") && jpgImagesAdded) {1194return true;1195}11961197return false;1198}119912001201private boolean isSupportedCopies(Copies copies) {1202CopiesSupported cs = (CopiesSupported)1203getSupportedAttributeValues(Copies.class, null, null);1204int[][] members = cs.getMembers();1205int min, max;1206if ((members.length > 0) && (members[0].length > 0)) {1207min = members[0][0];1208max = members[0][1];1209} else {1210min = 1;1211max = MAXCOPIES;1212}12131214int value = copies.getValue();1215return (value >= min && value <= max);1216}12171218private boolean isAutoSense(DocFlavor flavor) {1219if (flavor.equals(DocFlavor.BYTE_ARRAY.AUTOSENSE) ||1220flavor.equals(DocFlavor.INPUT_STREAM.AUTOSENSE) ||1221flavor.equals(DocFlavor.URL.AUTOSENSE)) {1222return true;1223}1224else {1225return false;1226}1227}12281229private synchronized boolean isSupportedMediaTray(MediaTray msn) {1230initAttributes();12311232if (mediaTrays != null) {1233for (int i=0; i<mediaTrays.length; i++) {1234if (msn.equals(mediaTrays[i])) {1235return true;1236}1237}1238}1239return false;1240}12411242private synchronized boolean isSupportedMedia(MediaSizeName msn) {1243initAttributes();12441245if (msn.equals((Media)getDefaultAttributeValue(Media.class))) {1246return true;1247}1248for (int i=0; i<mediaSizeNames.length; i++) {1249debug_println(debugPrefix+"isSupportedMedia, mediaSizeNames[i] "+mediaSizeNames[i]);1250if (msn.equals(mediaSizeNames[i])) {1251return true;1252}1253}1254return false;1255}12561257/* Return false if flavor is not null, pageable, nor printable and1258* Destination is part of attributes.1259*/1260private boolean1261isDestinationSupported(DocFlavor flavor, AttributeSet attributes) {12621263if ((attributes != null) &&1264(attributes.get(Destination.class) != null) &&1265!(flavor == null ||1266flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||1267flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {1268return false;1269}1270return true;1271}127212731274public boolean isAttributeValueSupported(Attribute attr,1275DocFlavor flavor,1276AttributeSet attributes) {1277if (attr == null) {1278throw new NullPointerException("null attribute");1279}1280if (flavor != null) {1281if (!isDocFlavorSupported(flavor)) {1282throw new IllegalArgumentException(flavor +1283" is an unsupported flavor");1284} else if (isAutoSense(flavor)) {1285return false;1286}1287}1288Class category = attr.getCategory();1289if (!isAttributeCategorySupported(category)) {1290return false;1291}12921293/* Test if the flavor is compatible with the attributes */1294if (!isDestinationSupported(flavor, attributes)) {1295return false;1296}12971298/* Test if the flavor is compatible with the category */1299if (attr.getCategory() == Chromaticity.class) {1300if ((flavor == null) ||1301flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||1302flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE) ||1303!isIPPSupportedImages(flavor.getMimeType())) {1304return attr == Chromaticity.COLOR;1305} else {1306return false;1307}1308} else if (attr.getCategory() == Copies.class) {1309return (flavor == null ||1310!(flavor.equals(DocFlavor.INPUT_STREAM.POSTSCRIPT) ||1311flavor.equals(DocFlavor.URL.POSTSCRIPT) ||1312flavor.equals(DocFlavor.BYTE_ARRAY.POSTSCRIPT))) &&1313isSupportedCopies((Copies)attr);13141315} else if (attr.getCategory() == Destination.class) {1316if (flavor == null ||1317flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||1318flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE)) {1319URI uri = ((Destination)attr).getURI();1320if ("file".equals(uri.getScheme()) &&1321!(uri.getSchemeSpecificPart().equals(""))) {1322return true;1323}1324}1325return false;1326} else if (attr.getCategory() == Media.class) {1327if (attr instanceof MediaSizeName) {1328return isSupportedMedia((MediaSizeName)attr);1329}1330if (attr instanceof MediaTray) {1331return isSupportedMediaTray((MediaTray)attr);1332}1333} else if (attr.getCategory() == PageRanges.class) {1334if (flavor != null &&1335!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||1336flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {1337return false;1338}1339} else if (attr.getCategory() == SheetCollate.class) {1340if (flavor != null &&1341!(flavor.equals(DocFlavor.SERVICE_FORMATTED.PAGEABLE) ||1342flavor.equals(DocFlavor.SERVICE_FORMATTED.PRINTABLE))) {1343return false;1344}1345} else if (attr.getCategory() == Sides.class) {1346Sides[] sidesArray = (Sides[])getSupportedAttributeValues(1347Sides.class,1348flavor,1349attributes);13501351if (sidesArray != null) {1352for (int i=0; i<sidesArray.length; i++) {1353if (sidesArray[i] == (Sides)attr) {1354return true;1355}1356}1357}1358return false;1359} else if (attr.getCategory() == OrientationRequested.class) {1360OrientationRequested[] orientArray =1361(OrientationRequested[])getSupportedAttributeValues(1362OrientationRequested.class,1363flavor,1364attributes);13651366if (orientArray != null) {1367for (int i=0; i<orientArray.length; i++) {1368if (orientArray[i] == (OrientationRequested)attr) {1369return true;1370}1371}1372}1373return false;1374}1375return true;1376}137713781379public synchronized Object1380getDefaultAttributeValue(Class<? extends Attribute> category)1381{1382if (category == null) {1383throw new NullPointerException("null category");1384}1385if (!Attribute.class.isAssignableFrom(category)) {1386throw new IllegalArgumentException(category +1387" is not an Attribute");1388}1389if (!isAttributeCategorySupported(category)) {1390return null;1391}13921393initAttributes();13941395String catName = null;1396for (int i=0; i < printReqAttribDefault.length; i++) {1397PrintRequestAttribute pra =1398(PrintRequestAttribute)printReqAttribDefault[i];1399if (pra.getCategory() == category) {1400catName = pra.getName();1401break;1402}1403}1404String attribName = catName+"-default";1405AttributeClass attribClass = (getAttMap != null) ?1406(AttributeClass)getAttMap.get(attribName) : null;14071408if (category == Copies.class) {1409if (attribClass != null) {1410return new Copies(attribClass.getIntValue());1411} else {1412return new Copies(1);1413}1414} else if (category == Chromaticity.class) {1415return Chromaticity.COLOR;1416} else if (category == Destination.class) {1417try {1418return new Destination((new File("out.ps")).toURI());1419} catch (SecurityException se) {1420try {1421return new Destination(new URI("file:out.ps"));1422} catch (URISyntaxException e) {1423return null;1424}1425}1426} else if (category == Fidelity.class) {1427return Fidelity.FIDELITY_FALSE;1428} else if (category == Finishings.class) {1429return Finishings.NONE;1430} else if (category == JobName.class) {1431return new JobName("Java Printing", null);1432} else if (category == JobSheets.class) {1433if (attribClass != null &&1434attribClass.getStringValue().equals("none")) {1435return JobSheets.NONE;1436} else {1437return JobSheets.STANDARD;1438}1439} else if (category == Media.class) {1440if (defaultMediaIndex == -1) {1441defaultMediaIndex = 0;1442}1443if (mediaSizeNames.length == 0) {1444String defaultCountry = Locale.getDefault().getCountry();1445if (defaultCountry != null &&1446(defaultCountry.equals("") ||1447defaultCountry.equals(Locale.US.getCountry()) ||1448defaultCountry.equals(Locale.CANADA.getCountry()))) {1449return MediaSizeName.NA_LETTER;1450} else {1451return MediaSizeName.ISO_A4;1452}1453}14541455if (attribClass != null) {1456String name = attribClass.getStringValue();1457if (isCupsPrinter) {1458return mediaSizeNames[defaultMediaIndex];1459} else {1460for (int i=0; i< mediaSizeNames.length; i++) {1461if (mediaSizeNames[i].toString().indexOf(name) != -1) {1462defaultMediaIndex = i;1463return mediaSizeNames[defaultMediaIndex];1464}1465}1466}1467}1468return mediaSizeNames[defaultMediaIndex];14691470} else if (category == MediaPrintableArea.class) {1471MediaPrintableArea[] mpas;1472if ((cps != null) &&1473((mpas = cps.getMediaPrintableArea()) != null)) {1474if (defaultMediaIndex == -1) {1475// initializes value of defaultMediaIndex1476getDefaultAttributeValue(Media.class);1477}1478return mpas[defaultMediaIndex];1479} else {1480String defaultCountry = Locale.getDefault().getCountry();1481float iw, ih;1482if (defaultCountry != null &&1483(defaultCountry.equals("") ||1484defaultCountry.equals(Locale.US.getCountry()) ||1485defaultCountry.equals(Locale.CANADA.getCountry()))) {1486iw = MediaSize.NA.LETTER.getX(Size2DSyntax.INCH) - 0.5f;1487ih = MediaSize.NA.LETTER.getY(Size2DSyntax.INCH) - 0.5f;1488} else {1489iw = MediaSize.ISO.A4.getX(Size2DSyntax.INCH) - 0.5f;1490ih = MediaSize.ISO.A4.getY(Size2DSyntax.INCH) - 0.5f;1491}1492return new MediaPrintableArea(0.25f, 0.25f, iw, ih,1493MediaPrintableArea.INCH);1494}1495} else if (category == NumberUp.class) {1496return new NumberUp(1); // for CUPS this is always 11497} else if (category == OrientationRequested.class) {1498if (attribClass != null) {1499switch (attribClass.getIntValue()) {1500default:1501case 3: return OrientationRequested.PORTRAIT;1502case 4: return OrientationRequested.LANDSCAPE;1503case 5: return OrientationRequested.REVERSE_LANDSCAPE;1504case 6: return OrientationRequested.REVERSE_PORTRAIT;1505}1506} else {1507return OrientationRequested.PORTRAIT;1508}1509} else if (category == PageRanges.class) {1510if (attribClass != null) {1511int[] range = attribClass.getIntRangeValue();1512return new PageRanges(range[0], range[1]);1513} else {1514return new PageRanges(1, Integer.MAX_VALUE);1515}1516} else if (category == RequestingUserName.class) {1517String userName = "";1518try {1519userName = System.getProperty("user.name", "");1520} catch (SecurityException se) {1521}1522return new RequestingUserName(userName, null);1523} else if (category == SheetCollate.class) {1524return SheetCollate.UNCOLLATED;1525} else if (category == Sides.class) {1526if (attribClass != null) {1527if (attribClass.getStringValue().endsWith("long-edge")) {1528return Sides.TWO_SIDED_LONG_EDGE;1529} else if (attribClass.getStringValue().endsWith(1530"short-edge")) {1531return Sides.TWO_SIDED_SHORT_EDGE;1532}1533}1534return Sides.ONE_SIDED;1535}15361537return null;1538}15391540public ServiceUIFactory getServiceUIFactory() {1541return null;1542}15431544public void wakeNotifier() {1545synchronized (this) {1546if (notifier != null) {1547notifier.wake();1548}1549}1550}15511552public void addPrintServiceAttributeListener(1553PrintServiceAttributeListener listener) {1554synchronized (this) {1555if (listener == null) {1556return;1557}1558if (notifier == null) {1559notifier = new ServiceNotifier(this);1560}1561notifier.addListener(listener);1562}1563}15641565public void removePrintServiceAttributeListener(1566PrintServiceAttributeListener listener) {1567synchronized (this) {1568if (listener == null || notifier == null ) {1569return;1570}1571notifier.removeListener(listener);1572if (notifier.isEmpty()) {1573notifier.stopNotifier();1574notifier = null;1575}1576}1577}15781579String getDest() {1580return printer;1581}15821583public String getName() {1584/*1585* Mac is using printer-info IPP attribute for its human-readable printer1586* name and is also the identifier used in NSPrintInfo:setPrinter.1587*/1588if (PrintServiceLookupProvider.isMac()) {1589PrintServiceAttributeSet psaSet = this.getAttributes();1590if (psaSet != null) {1591PrinterInfo pName = (PrinterInfo)psaSet.get(PrinterInfo.class);1592if (pName != null) {1593return pName.toString();1594}1595}1596}1597return printer;1598}159916001601public boolean usesClass(Class c) {1602return (c == sun.print.PSPrinterJob.class);1603}160416051606public static HttpURLConnection getIPPConnection(URL url) {1607HttpURLConnection connection;1608URLConnection urlc;1609try {1610urlc = url.openConnection();1611} catch (java.io.IOException ioe) {1612return null;1613}1614if (!(urlc instanceof HttpURLConnection)) {1615return null;1616}1617connection = (HttpURLConnection)urlc;1618connection.setUseCaches(false);1619connection.setDefaultUseCaches(false);1620connection.setDoInput(true);1621connection.setDoOutput(true);1622connection.setRequestProperty("Content-type", "application/ipp");1623return connection;1624}162516261627public synchronized boolean isPostscript() {1628if (isPS == null) {1629isPS = Boolean.TRUE;1630if (isCupsPrinter) {1631try {1632urlConnection = getIPPConnection(1633new URL(myURL+".ppd"));16341635InputStream is = urlConnection.getInputStream();1636if (is != null) {1637BufferedReader d =1638new BufferedReader(new InputStreamReader(is,1639Charset.forName("ISO-8859-1")));1640String lineStr;1641while ((lineStr = d.readLine()) != null) {1642if (lineStr.startsWith("*cupsFilter:")) {1643isPS = Boolean.FALSE;1644break;1645}1646}1647}1648} catch (java.io.IOException e) {1649debug_println(" isPostscript, e= "+e);1650/* if PPD is not found, this may be a raw printer1651and in this case it is assumed that it is a1652Postscript printer */1653// do nothing1654}1655}1656}1657return isPS.booleanValue();1658}165916601661private void opGetAttributes() {1662try {1663debug_println(debugPrefix+"opGetAttributes myURI "+myURI+" myURL "+myURL);16641665AttributeClass attClNoUri[] = {1666AttributeClass.ATTRIBUTES_CHARSET,1667AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE};16681669AttributeClass attCl[] = {1670AttributeClass.ATTRIBUTES_CHARSET,1671AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,1672new AttributeClass("printer-uri",1673AttributeClass.TAG_URI,1674""+myURI)};16751676OutputStream os = (OutputStream)java.security.AccessController.1677doPrivileged(new java.security.PrivilegedAction() {1678public Object run() {1679try {1680return urlConnection.getOutputStream();1681} catch (Exception e) {1682}1683return null;1684}1685});16861687if (os == null) {1688return;1689}16901691boolean success = (myURI == null) ?1692writeIPPRequest(os, OP_GET_ATTRIBUTES, attClNoUri) :1693writeIPPRequest(os, OP_GET_ATTRIBUTES, attCl);1694if (success) {1695InputStream is = null;1696if ((is = urlConnection.getInputStream())!=null) {1697HashMap[] responseMap = readIPPResponse(is);16981699if (responseMap != null && responseMap.length > 0) {1700getAttMap = responseMap[0];1701// If there is extra hashmap created due to duplicate1702// key/attribute present in IPPresponse, then use that1703// map too by appending to getAttMap after removing the1704// duplicate key/value1705if (responseMap.length > 1) {1706for (int i = 1; i < responseMap.length; i++) {1707Set<Map.Entry<String, AttributeClass>> entries = responseMap[i].entrySet();1708for (Map.Entry<String, AttributeClass> entry : entries) {1709if (!getAttMap.containsKey(entry.getValue())) {1710getAttMap.put(entry.getKey(), entry.getValue());1711}1712}1713}1714}1715}1716} else {1717debug_println(debugPrefix+"opGetAttributes - null input stream");1718}1719is.close();1720}1721os.close();1722} catch (java.io.IOException e) {1723debug_println(debugPrefix+"opGetAttributes - input/output stream: "+e);1724}1725}172617271728public static boolean writeIPPRequest(OutputStream os,1729String operCode,1730AttributeClass[] attCl) {1731OutputStreamWriter osw;1732try {1733osw = new OutputStreamWriter(os, "UTF-8");1734} catch (java.io.UnsupportedEncodingException exc) {1735debug_println(debugPrefix+"writeIPPRequest, UTF-8 not supported? Exception: "+exc);1736return false;1737}1738debug_println(debugPrefix+"writeIPPRequest, op code= "+operCode);1739char[] opCode = new char[2];1740opCode[0] = (char)Byte.parseByte(operCode.substring(0,2), 16);1741opCode[1] = (char)Byte.parseByte(operCode.substring(2,4), 16);1742char[] bytes = {0x01, 0x01, 0x00, 0x01};1743try {1744osw.write(bytes, 0, 2); // version number1745osw.write(opCode, 0, 2); // operation code1746bytes[0] = 0x00; bytes[1] = 0x00;1747osw.write(bytes, 0, 4); // request ID #117481749bytes[0] = 0x01; // operation-group-tag1750osw.write(bytes[0]);17511752String valStr;1753char[] lenStr;17541755AttributeClass ac;1756for (int i=0; i < attCl.length; i++) {1757ac = attCl[i];1758osw.write(ac.getType()); // value tag17591760lenStr = ac.getLenChars();1761osw.write(lenStr, 0, 2); // length1762osw.write(""+ac, 0, ac.getName().length());17631764// check if string range (0x35 -> 0x49)1765if (ac.getType() >= AttributeClass.TAG_TEXT_LANGUAGE &&1766ac.getType() <= AttributeClass.TAG_MIME_MEDIATYPE){1767valStr = (String)ac.getObjectValue();1768bytes[0] = 0; bytes[1] = (char)valStr.length();1769osw.write(bytes, 0, 2);1770osw.write(valStr, 0, valStr.length());1771} // REMIND: need to support other value tags but for CUPS1772// string is all we need.1773}17741775osw.write(GRPTAG_END_ATTRIBUTES);1776osw.flush();1777osw.close();1778} catch (java.io.IOException ioe) {1779debug_println(debugPrefix+"writeIPPRequest, IPPPrintService Exception in writeIPPRequest: "+ioe);1780return false;1781}1782return true;1783}178417851786public static HashMap[] readIPPResponse(InputStream inputStream) {17871788if (inputStream == null) {1789return null;1790}17911792byte response[] = new byte[MAX_ATTRIBUTE_LENGTH];1793try {17941795DataInputStream ois = new DataInputStream(inputStream);17961797// read status and ID1798if ((ois.read(response, 0, 8) > -1) &&1799(response[2] == STATUSCODE_SUCCESS)) {18001801ByteArrayOutputStream outObj;1802int counter=0;1803short len = 0;1804String attribStr = null;1805// assign default value1806byte valTagByte = AttributeClass.TAG_KEYWORD;1807ArrayList respList = new ArrayList();1808HashMap responseMap = new HashMap();18091810response[0] = ois.readByte();18111812// check for group tags1813while ((response[0] >= GRPTAG_OP_ATTRIBUTES) &&1814(response[0] <= GRPTAG_PRINTER_ATTRIBUTES)1815&& (response[0] != GRPTAG_END_ATTRIBUTES)) {1816debug_println(debugPrefix+"readIPPResponse, checking group tag, response[0]= "+1817response[0]);18181819outObj = new ByteArrayOutputStream();1820//make sure counter and attribStr are re-initialized1821counter = 0;1822attribStr = null;18231824// read value tag1825response[0] = ois.readByte();1826while (response[0] >= AttributeClass.TAG_UNSUPPORTED_VALUE &&1827response[0] <= AttributeClass.TAG_MEMBER_ATTRNAME) {1828// read name length1829len = ois.readShort();18301831// If current value is not part of previous attribute1832// then close stream and add it to HashMap.1833// It is part of previous attribute if name length=0.1834if ((len != 0) && (attribStr != null)) {1835//last byte is the total # of values1836outObj.write(counter);1837outObj.flush();1838outObj.close();1839byte outArray[] = outObj.toByteArray();18401841// if key exists, new HashMap1842if (responseMap.containsKey(attribStr)) {1843respList.add(responseMap);1844responseMap = new HashMap();1845}18461847// exclude those that are unknown1848if (valTagByte >= AttributeClass.TAG_INT) {1849AttributeClass ac =1850new AttributeClass(attribStr,1851valTagByte,1852outArray);18531854responseMap.put(ac.getName(), ac);1855debug_println(debugPrefix+ "readIPPResponse "+ac);1856}18571858outObj = new ByteArrayOutputStream();1859counter = 0; //reset counter1860}1861//check if this is new value tag1862if (counter == 0) {1863valTagByte = response[0];1864}1865// read attribute name1866if (len != 0) {1867// read "len" characters1868// make sure it doesn't exceed the maximum1869if (len > MAX_ATTRIBUTE_LENGTH) {1870response = new byte[len]; // expand as needed1871}1872ois.read(response, 0, len);1873attribStr = new String(response, 0, len);1874}1875// read value length1876len = ois.readShort();1877// write name length1878outObj.write(len);1879// read value, make sure it doesn't exceed the maximum1880if (len > MAX_ATTRIBUTE_LENGTH) {1881response = new byte[len]; // expand as needed1882}1883ois.read(response, 0, len);1884// write value of "len" length1885outObj.write(response, 0, len);1886counter++;1887// read next byte1888response[0] = ois.readByte();1889}18901891if (attribStr != null) {1892outObj.write(counter);1893outObj.flush();1894outObj.close();18951896// if key exists in old HashMap, new HashMap1897if ((counter != 0) &&1898responseMap.containsKey(attribStr)) {1899respList.add(responseMap);1900responseMap = new HashMap();1901}19021903byte outArray[] = outObj.toByteArray();19041905AttributeClass ac =1906new AttributeClass(attribStr,1907valTagByte,1908outArray);1909responseMap.put(ac.getName(), ac);1910}1911}1912ois.close();1913if ((responseMap != null) && (responseMap.size() > 0)) {1914respList.add(responseMap);1915}1916return (HashMap[])respList.toArray(1917new HashMap[respList.size()]);1918} else {1919debug_println(debugPrefix+1920"readIPPResponse client error, IPP status code: 0x"+1921toHex(response[2]) + toHex(response[3]));1922return null;1923}19241925} catch (java.io.IOException e) {1926debug_println(debugPrefix+"readIPPResponse: "+e);1927if (debugPrint) {1928e.printStackTrace();1929}1930return null;1931}1932}19331934private static String toHex(byte v) {1935String s = Integer.toHexString(v&0xff);1936return (s.length() == 2) ? s : "0"+s;1937}19381939public String toString() {1940return "IPP Printer : " + getName();1941}19421943public boolean equals(Object obj) {1944return (obj == this ||1945(obj instanceof IPPPrintService &&1946((IPPPrintService)obj).getName().equals(getName())));1947}19481949public int hashCode() {1950return this.getClass().hashCode()+getName().hashCode();1951}1952}195319541955