1 /*
   2  * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.print;
  27 
  28 import java.net.URL;
  29 import java.net.HttpURLConnection;
  30 import java.io.OutputStream;
  31 import java.io.InputStream;
  32 import java.util.ArrayList;
  33 import java.util.HashMap;
  34 import sun.print.IPPPrintService;
  35 import sun.print.CustomMediaSizeName;
  36 import sun.print.CustomMediaTray;
  37 import javax.print.attribute.standard.Media;
  38 import javax.print.attribute.standard.MediaSizeName;
  39 import javax.print.attribute.standard.MediaSize;
  40 import javax.print.attribute.standard.MediaTray;
  41 import javax.print.attribute.standard.MediaPrintableArea;
  42 import javax.print.attribute.Size2DSyntax;
  43 import javax.print.attribute.Attribute;
  44 import javax.print.attribute.EnumSyntax;
  45 import javax.print.attribute.standard.PrinterName;
  46 
  47 
  48 public class CUPSPrinter  {
  49     private static final String debugPrefix = "CUPSPrinter>> ";
  50     private static final double PRINTER_DPI = 72.0;
  51     private boolean initialized;
  52     private static native String getCupsServer();
  53     private static native int getCupsPort();
  54     private static native boolean canConnect(String server, int port);
  55     private static native boolean initIDs();
  56     // These functions need to be synchronized as
  57     // CUPS does not support multi-threading.
  58     private static synchronized native String[] getMedia(String printer);
  59     private static synchronized native float[] getPageSizes(String printer);
  60     //public static boolean useIPPMedia = false; will be used later
  61 
  62     private MediaPrintableArea[] cupsMediaPrintables;
  63     private MediaSizeName[] cupsMediaSNames;
  64     private CustomMediaSizeName[] cupsCustomMediaSNames;
  65     private MediaTray[] cupsMediaTrays;
  66 
  67     public  int nPageSizes = 0;
  68     public  int nTrays = 0;
  69     private  String[] media;
  70     private  float[] pageSizes;
  71     private String printer;
  72 
  73     private static boolean libFound;
  74     private static String cupsServer = null;
  75     private static int cupsPort = 0;
  76 
  77     static {
  78         // load awt library to access native code
  79         java.security.AccessController.doPrivileged(
  80             new java.security.PrivilegedAction<Void>() {
  81                 public Void run() {
  82                     System.loadLibrary("awt");
  83                     return null;
  84                 }
  85             });
  86         libFound = initIDs();
  87         if (libFound) {
  88            cupsServer = getCupsServer();
  89            cupsPort = getCupsPort();
  90         }
  91     }
  92 
  93 
  94     CUPSPrinter (String printerName) {
  95         if (printerName == null) {
  96             throw new IllegalArgumentException("null printer name");
  97         }
  98         printer = printerName;
  99         cupsMediaSNames = null;
 100         cupsMediaPrintables = null;
 101         cupsMediaTrays = null;
 102         initialized = false;
 103 
 104         if (!libFound) {
 105             throw new RuntimeException("cups lib not found");
 106         } else {
 107             // get page + tray names
 108             media =  getMedia(printer);
 109             if (media == null) {
 110                 // either PPD file is not found or printer is unknown
 111                 throw new RuntimeException("error getting PPD");
 112             }
 113 
 114             // get sizes
 115             pageSizes = getPageSizes(printer);
 116             if (pageSizes != null) {
 117                 nPageSizes = pageSizes.length/6;
 118 
 119                 nTrays = media.length/2-nPageSizes;
 120                 assert (nTrays >= 0);
 121             }
 122         }
 123     }
 124 
 125 
 126     /**
 127      * Returns array of MediaSizeNames derived from PPD.
 128      */
 129     public MediaSizeName[] getMediaSizeNames() {
 130         initMedia();
 131         return cupsMediaSNames;
 132     }
 133 
 134 
 135     /**
 136      * Returns array of Custom MediaSizeNames derived from PPD.
 137      */
 138     public CustomMediaSizeName[] getCustomMediaSizeNames() {
 139         initMedia();
 140         return cupsCustomMediaSNames;
 141     }
 142 
 143 
 144     /**
 145      * Returns array of MediaPrintableArea derived from PPD.
 146      */
 147     public MediaPrintableArea[] getMediaPrintableArea() {
 148         initMedia();
 149         return cupsMediaPrintables;
 150     }
 151 
 152     /**
 153      * Returns array of MediaTrays derived from PPD.
 154      */
 155     public MediaTray[] getMediaTrays() {
 156         initMedia();
 157         return cupsMediaTrays;
 158     }
 159 
 160 
 161     /**
 162      * Initialize media by translating PPD info to PrintService attributes.
 163      */
 164     private synchronized void initMedia() {
 165         if (initialized) {
 166             return;
 167         } else {
 168             initialized = true;
 169         }
 170 
 171         if (pageSizes == null) {
 172             return;
 173         }
 174 
 175         cupsMediaPrintables = new MediaPrintableArea[nPageSizes];
 176         cupsMediaSNames = new MediaSizeName[nPageSizes];
 177         cupsCustomMediaSNames = new CustomMediaSizeName[nPageSizes];
 178 
 179         CustomMediaSizeName msn;
 180         MediaPrintableArea mpa;
 181         float length, width, x, y, w, h;
 182 
 183         // initialize names and printables
 184         for (int i=0; i<nPageSizes; i++) {
 185             // media width and length
 186             width = (float)(pageSizes[i*6]/PRINTER_DPI);
 187             length = (float)(pageSizes[i*6+1]/PRINTER_DPI);
 188             // media printable area
 189             x = (float)(pageSizes[i*6+2]/PRINTER_DPI);
 190             h = (float)(pageSizes[i*6+3]/PRINTER_DPI);
 191             w = (float)(pageSizes[i*6+4]/PRINTER_DPI);
 192             y = (float)(pageSizes[i*6+5]/PRINTER_DPI);
 193 
 194             msn = new CustomMediaSizeName(media[i*2], media[i*2+1],
 195                                           width, length);
 196 
 197             // add to list of standard MediaSizeNames
 198             if ((cupsMediaSNames[i] = msn.getStandardMedia()) == null) {
 199                 // add custom if no matching standard media
 200                 cupsMediaSNames[i] = msn;
 201 
 202                 // add this new custom msn to MediaSize array
 203                 if ((width > 0.0) && (length > 0.0)) {
 204                     new MediaSize(width, length,
 205                                   Size2DSyntax.INCH, msn);
 206                 }
 207             }
 208 
 209             // add to list of custom MediaSizeName
 210             // for internal use of IPPPrintService
 211             cupsCustomMediaSNames[i] = msn;
 212 
 213             mpa = null;
 214             try {
 215                 mpa = new MediaPrintableArea(x, y, w, h,
 216                                              MediaPrintableArea.INCH);
 217             } catch (IllegalArgumentException e) {
 218                 if (width > 0 && length > 0) {
 219                     mpa = new MediaPrintableArea(0, 0, width, length,
 220                                              MediaPrintableArea.INCH);
 221                 }
 222             }
 223             cupsMediaPrintables[i] = mpa;
 224         }
 225 
 226         // initialize trays
 227         cupsMediaTrays = new MediaTray[nTrays];
 228 
 229         MediaTray mt;
 230         for (int i=0; i<nTrays; i++) {
 231             mt = new CustomMediaTray(media[(nPageSizes+i)*2],
 232                                      media[(nPageSizes+i)*2+1]);
 233             cupsMediaTrays[i] = mt;
 234         }
 235 
 236     }
 237 
 238     /**
 239      * Get CUPS default printer using IPP.
 240      */
 241     public static String getDefaultPrinter() {
 242         try {
 243             URL url = new URL("http", getServer(), getPort(), "");
 244             final HttpURLConnection urlConnection =
 245                 IPPPrintService.getIPPConnection(url);
 246 
 247             if (urlConnection != null) {
 248                 OutputStream os = (OutputStream)java.security.AccessController.
 249                     doPrivileged(new java.security.PrivilegedAction() {
 250                         public Object run() {
 251                             try {
 252                                 return urlConnection.getOutputStream();
 253                             } catch (Exception e) {
 254                             }
 255                             return null;
 256                         }
 257                     });
 258 
 259                 if (os == null) {
 260                     return null;
 261                 }
 262 
 263                 AttributeClass attCl[] = {
 264                     AttributeClass.ATTRIBUTES_CHARSET,
 265                     AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
 266                     new AttributeClass("requested-attributes",
 267                                        AttributeClass.TAG_KEYWORD,
 268                                        "printer-name")
 269                 };
 270 
 271                 if (IPPPrintService.writeIPPRequest(os,
 272                                         IPPPrintService.OP_CUPS_GET_DEFAULT,
 273                                         attCl)) {
 274 
 275                     HashMap defaultMap = null;
 276                     InputStream is = urlConnection.getInputStream();
 277                     HashMap[] responseMap = IPPPrintService.readIPPResponse(
 278                                          is);
 279                     is.close();
 280 
 281                     if (responseMap.length > 0) {
 282                         defaultMap = responseMap[0];
 283                     }
 284 
 285                     if (defaultMap == null) {
 286                         os.close();
 287                         urlConnection.disconnect();
 288                         return null;
 289                     }
 290 
 291                     AttributeClass attribClass = (AttributeClass)
 292                         defaultMap.get("printer-name");
 293 
 294                     if (attribClass != null) {
 295                         String nameStr = attribClass.getStringValue();
 296                         os.close();
 297                         urlConnection.disconnect();
 298                         return nameStr;
 299                     }
 300                 }
 301                 os.close();
 302                 urlConnection.disconnect();
 303             }
 304         } catch (Exception e) {
 305         }
 306         return null;
 307     }
 308 
 309 
 310     /**
 311      * Get list of all CUPS printers using IPP.
 312      */
 313     public static String[] getAllPrinters() {
 314         try {
 315             URL url = new URL("http", getServer(), getPort(), "");
 316 
 317             final HttpURLConnection urlConnection =
 318                 IPPPrintService.getIPPConnection(url);
 319 
 320             if (urlConnection != null) {
 321                 OutputStream os = (OutputStream)java.security.AccessController.
 322                     doPrivileged(new java.security.PrivilegedAction() {
 323                         public Object run() {
 324                             try {
 325                                 return urlConnection.getOutputStream();
 326                             } catch (Exception e) {
 327                             }
 328                             return null;
 329                         }
 330                     });
 331 
 332                 if (os == null) {
 333                     return null;
 334                 }
 335 
 336                 AttributeClass attCl[] = {
 337                     AttributeClass.ATTRIBUTES_CHARSET,
 338                     AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
 339                     new AttributeClass("requested-attributes",
 340                                        AttributeClass.TAG_KEYWORD,
 341                                        "printer-uri-supported")
 342                 };
 343 
 344                 if (IPPPrintService.writeIPPRequest(os,
 345                                 IPPPrintService.OP_CUPS_GET_PRINTERS, attCl)) {
 346 
 347                     InputStream is = urlConnection.getInputStream();
 348                     HashMap[] responseMap =
 349                         IPPPrintService.readIPPResponse(is);
 350 
 351                     is.close();
 352                     os.close();
 353                     urlConnection.disconnect();
 354 
 355                     if (responseMap == null || responseMap.length == 0) {
 356                         return null;
 357                     }
 358 
 359                     ArrayList printerNames = new ArrayList();
 360                     for (int i=0; i< responseMap.length; i++) {
 361                         AttributeClass attribClass = (AttributeClass)
 362                             responseMap[i].get("printer-uri-supported");
 363 
 364                         if (attribClass != null) {
 365                             String nameStr = attribClass.getStringValue();
 366                             printerNames.add(nameStr);
 367                         }
 368                     }
 369                     return (String[])printerNames.toArray(new String[] {});
 370                 } else {
 371                     os.close();
 372                     urlConnection.disconnect();
 373                 }
 374             }
 375 
 376         } catch (Exception e) {
 377         }
 378         return null;
 379 
 380     }
 381 
 382     /**
 383      * Returns CUPS server name.
 384      */
 385     public static String getServer() {
 386         return cupsServer;
 387     }
 388 
 389     /**
 390      * Returns CUPS port number.
 391      */
 392     public static int getPort() {
 393         return cupsPort;
 394     }
 395 
 396     /**
 397      * Detects if CUPS is running.
 398      */
 399     public static boolean isCupsRunning() {
 400         IPPPrintService.debug_println(debugPrefix+"libFound "+libFound);
 401         if (libFound) {
 402             IPPPrintService.debug_println(debugPrefix+"CUPS server "+getServer()+
 403                                           " port "+getPort());
 404             return canConnect(getServer(), getPort());
 405         } else {
 406             return false;
 407         }
 408     }
 409 
 410 
 411 }