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 ---