1 /*
   2  * Copyright (c) 2003, 2014, 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      * Returns 2 values - index 0 is printer name, index 1 is the uri.
 241      */
 242     static String[] getDefaultPrinter() {
 243         try {
 244             URL url = new URL("http", getServer(), getPort(), "");
 245             final HttpURLConnection urlConnection =
 246                 IPPPrintService.getIPPConnection(url);
 247 
 248             if (urlConnection != null) {
 249                 OutputStream os = (OutputStream)java.security.AccessController.
 250                     doPrivileged(new java.security.PrivilegedAction() {
 251                         public Object run() {
 252                             try {
 253                                 return urlConnection.getOutputStream();
 254                             } catch (Exception e) {

 255                             }
 256                             return null;
 257                         }
 258                     });
 259 
 260                 if (os == null) {
 261                     return null;
 262                 }
 263 
 264                 AttributeClass attCl[] = {
 265                     AttributeClass.ATTRIBUTES_CHARSET,
 266                     AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
 267                     new AttributeClass("requested-attributes",
 268                                        AttributeClass.TAG_URI,
 269                                        "printer-uri")
 270                 };
 271 
 272                 if (IPPPrintService.writeIPPRequest(os,
 273                                         IPPPrintService.OP_CUPS_GET_DEFAULT,
 274                                         attCl)) {
 275 
 276                     HashMap defaultMap = null;
 277                     String[] printerInfo = new String[2];
 278                     InputStream is = urlConnection.getInputStream();
 279                     HashMap[] responseMap = IPPPrintService.readIPPResponse(
 280                                          is);
 281                     is.close();
 282 
 283                     if (responseMap != null && responseMap.length > 0) {
 284                         defaultMap = responseMap[0];



 285                     }
 286 
 287                     if (defaultMap == null) {
 288                         os.close();
 289                         urlConnection.disconnect();
 290 
 291                         /* CUPS on OS X, as initially configured, considers the
 292                          * default printer to be the last one used that's
 293                          * presently available. So if no default was
 294                          * reported, exec lpstat -d which has all the Apple
 295                          * special behaviour for this built in.
 296                          */
 297                          if (UnixPrintServiceLookup.isMac()) {
 298                              printerInfo[0] = UnixPrintServiceLookup.
 299                                                    getDefaultPrinterNameSysV();
 300                              printerInfo[1] = null;
 301                              return printerInfo.clone();
 302                          } else {
 303                              return null;
 304                          }
 305                     }
 306 
 307 
 308                     AttributeClass attribClass = (AttributeClass)
 309                         defaultMap.get("printer-name");
 310 
 311                     if (attribClass != null) {
 312                         printerInfo[0] = attribClass.getStringValue();
 313                         attribClass = (AttributeClass)defaultMap.get("device-uri");



 314                         if (attribClass != null) {
 315                             printerInfo[1] = attribClass.getStringValue();
 316                         } else {
 317                             printerInfo[1] = null;
 318                         }
 319                         os.close();
 320                         urlConnection.disconnect();
 321                         return printerInfo.clone();
 322                     }
 323                 }
 324                 os.close();
 325                 urlConnection.disconnect();
 326             }
 327         } catch (Exception e) {
 328         }
 329         return null;
 330     }
 331 
 332 
 333     /**
 334      * Get list of all CUPS printers using IPP.
 335      */
 336     static String[] getAllPrinters() {
 337         try {
 338             URL url = new URL("http", getServer(), getPort(), "");
 339 
 340             final HttpURLConnection urlConnection =
 341                 IPPPrintService.getIPPConnection(url);
 342 
 343             if (urlConnection != null) {
 344                 OutputStream os = (OutputStream)java.security.AccessController.
 345                     doPrivileged(new java.security.PrivilegedAction() {
 346                         public Object run() {
 347                             try {
 348                                 return urlConnection.getOutputStream();
 349                             } catch (Exception e) {
 350                             }
 351                             return null;
 352                         }
 353                     });
 354 
 355                 if (os == null) {
 356                     return null;
 357                 }
 358 
 359                 AttributeClass attCl[] = {
 360                     AttributeClass.ATTRIBUTES_CHARSET,
 361                     AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
 362                     new AttributeClass("requested-attributes",
 363                                        AttributeClass.TAG_KEYWORD,
 364                                        "printer-uri-supported")
 365                 };
 366 
 367                 if (IPPPrintService.writeIPPRequest(os,
 368                                 IPPPrintService.OP_CUPS_GET_PRINTERS, attCl)) {
 369 
 370                     InputStream is = urlConnection.getInputStream();
 371                     HashMap[] responseMap =
 372                         IPPPrintService.readIPPResponse(is);
 373 
 374                     is.close();
 375                     os.close();
 376                     urlConnection.disconnect();
 377 
 378                     if (responseMap == null || responseMap.length == 0) {
 379                         return null;
 380                     }
 381 
 382                     ArrayList printerNames = new ArrayList();
 383                     for (int i=0; i< responseMap.length; i++) {
 384                         AttributeClass attribClass = (AttributeClass)
 385                             responseMap[i].get("printer-uri-supported");
 386 
 387                         if (attribClass != null) {
 388                             String nameStr = attribClass.getStringValue();
 389                             printerNames.add(nameStr);
 390                         }
 391                     }
 392                     return (String[])printerNames.toArray(new String[] {});
 393                 } else {
 394                     os.close();
 395                     urlConnection.disconnect();
 396                 }
 397             }
 398 
 399         } catch (Exception e) {
 400         }
 401         return null;
 402 
 403     }
 404 
 405     /**
 406      * Returns CUPS server name.
 407      */
 408     public static String getServer() {
 409         return cupsServer;
 410     }
 411 
 412     /**
 413      * Returns CUPS port number.
 414      */
 415     public static int getPort() {
 416         return cupsPort;
 417     }
 418 
 419     /**
 420      * Detects if CUPS is running.
 421      */
 422     public static boolean isCupsRunning() {
 423         IPPPrintService.debug_println(debugPrefix+"libFound "+libFound);
 424         if (libFound) {
 425             IPPPrintService.debug_println(debugPrefix+"CUPS server "+getServer()+
 426                                           " port "+getPort());
 427             return canConnect(getServer(), getPort());
 428         } else {
 429             return false;
 430         }
 431     }
 432 
 433 
 434 }
--- EOF ---