Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java
66645 views
1
/*
2
* Copyright (c) 2003, 2021, 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.standard.PrinterResolution;
43
import javax.print.attribute.Size2DSyntax;
44
import javax.print.attribute.Attribute;
45
import javax.print.attribute.EnumSyntax;
46
import javax.print.attribute.standard.PrinterName;
47
48
49
@SuppressWarnings("removal")
50
public class CUPSPrinter {
51
private static final String debugPrefix = "CUPSPrinter>> ";
52
private static final double PRINTER_DPI = 72.0;
53
private boolean initialized;
54
private static native String getCupsServer();
55
private static native int getCupsPort();
56
private static native String getCupsDefaultPrinter();
57
private static native String[] getCupsDefaultPrinters();
58
private static native boolean canConnect(String server, int port);
59
private static native boolean initIDs();
60
// These functions need to be synchronized as
61
// CUPS does not support multi-threading.
62
private static synchronized native String[] getMedia(String printer);
63
private static synchronized native float[] getPageSizes(String printer);
64
private static synchronized native void
65
getResolutions(String printer, ArrayList<Integer> resolutionList);
66
//public static boolean useIPPMedia = false; will be used later
67
68
private MediaPrintableArea[] cupsMediaPrintables;
69
private MediaSizeName[] cupsMediaSNames;
70
private CustomMediaSizeName[] cupsCustomMediaSNames;
71
private MediaTray[] cupsMediaTrays;
72
73
public int nPageSizes = 0;
74
public int nTrays = 0;
75
private String[] media;
76
private float[] pageSizes;
77
int[] resolutionsArray;
78
private String printer;
79
80
private static boolean libFound;
81
private static String cupsServer = null;
82
private static String domainSocketPathname = null;
83
private static int cupsPort = 0;
84
85
static {
86
// load awt library to access native code
87
java.security.AccessController.doPrivileged(
88
new java.security.PrivilegedAction<Void>() {
89
public Void run() {
90
System.loadLibrary("awt");
91
return null;
92
}
93
});
94
libFound = initIDs();
95
if (libFound) {
96
cupsServer = getCupsServer();
97
// Is this a local domain socket pathname?
98
if (cupsServer != null && cupsServer.startsWith("/")) {
99
if (isSandboxedApp()) {
100
domainSocketPathname = cupsServer;
101
}
102
cupsServer = "localhost";
103
}
104
cupsPort = getCupsPort();
105
}
106
}
107
108
109
CUPSPrinter (String printerName) {
110
if (printerName == null) {
111
throw new IllegalArgumentException("null printer name");
112
}
113
printer = printerName;
114
cupsMediaSNames = null;
115
cupsMediaPrintables = null;
116
cupsMediaTrays = null;
117
initialized = false;
118
119
if (!libFound) {
120
throw new RuntimeException("cups lib not found");
121
} else {
122
// get page + tray names
123
media = getMedia(printer);
124
if (media == null) {
125
// either PPD file is not found or printer is unknown
126
throw new RuntimeException("error getting PPD");
127
}
128
129
// get sizes
130
pageSizes = getPageSizes(printer);
131
if (pageSizes != null) {
132
nPageSizes = pageSizes.length/6;
133
134
nTrays = media.length/2-nPageSizes;
135
assert (nTrays >= 0);
136
}
137
ArrayList<Integer> resolutionList = new ArrayList<>();
138
getResolutions(printer, resolutionList);
139
resolutionsArray = new int[resolutionList.size()];
140
for (int i=0; i < resolutionList.size(); i++) {
141
resolutionsArray[i] = resolutionList.get(i);
142
}
143
}
144
}
145
146
147
/**
148
* Returns array of MediaSizeNames derived from PPD.
149
*/
150
MediaSizeName[] getMediaSizeNames() {
151
initMedia();
152
return cupsMediaSNames;
153
}
154
155
156
/**
157
* Returns array of Custom MediaSizeNames derived from PPD.
158
*/
159
CustomMediaSizeName[] getCustomMediaSizeNames() {
160
initMedia();
161
return cupsCustomMediaSNames;
162
}
163
164
public int getDefaultMediaIndex() {
165
return ((pageSizes.length >1) ? (int)(pageSizes[pageSizes.length -1]) : 0);
166
}
167
168
/**
169
* Returns array of MediaPrintableArea derived from PPD.
170
*/
171
MediaPrintableArea[] getMediaPrintableArea() {
172
initMedia();
173
return cupsMediaPrintables;
174
}
175
176
/**
177
* Returns array of MediaTrays derived from PPD.
178
*/
179
MediaTray[] getMediaTrays() {
180
initMedia();
181
return cupsMediaTrays;
182
}
183
184
/**
185
* return the raw packed array of supported printer resolutions.
186
*/
187
int[] getRawResolutions() {
188
return resolutionsArray;
189
}
190
191
/**
192
* Initialize media by translating PPD info to PrintService attributes.
193
*/
194
private synchronized void initMedia() {
195
if (initialized) {
196
return;
197
} else {
198
initialized = true;
199
}
200
201
if (pageSizes == null) {
202
return;
203
}
204
205
cupsMediaPrintables = new MediaPrintableArea[nPageSizes];
206
cupsMediaSNames = new MediaSizeName[nPageSizes];
207
cupsCustomMediaSNames = new CustomMediaSizeName[nPageSizes];
208
209
CustomMediaSizeName msn;
210
MediaPrintableArea mpa;
211
float length, width, x, y, w, h;
212
213
// initialize names and printables
214
for (int i=0; i<nPageSizes; i++) {
215
// media width and length
216
width = (float)(pageSizes[i*6]/PRINTER_DPI);
217
length = (float)(pageSizes[i*6+1]/PRINTER_DPI);
218
// media printable area
219
x = (float)(pageSizes[i*6+2]/PRINTER_DPI);
220
h = (float)(pageSizes[i*6+3]/PRINTER_DPI);
221
w = (float)(pageSizes[i*6+4]/PRINTER_DPI);
222
y = (float)(pageSizes[i*6+5]/PRINTER_DPI);
223
224
msn = new CustomMediaSizeName(media[i*2], media[i*2+1],
225
width, length);
226
227
// add to list of standard MediaSizeNames
228
if ((cupsMediaSNames[i] = msn.getStandardMedia()) == null) {
229
// add custom if no matching standard media
230
cupsMediaSNames[i] = msn;
231
232
// add this new custom msn to MediaSize array
233
if ((width > 0.0) && (length > 0.0)) {
234
try {
235
new MediaSize(width, length,
236
Size2DSyntax.INCH, msn);
237
} catch (IllegalArgumentException e) {
238
/* PDF printer in Linux for Ledger paper causes
239
"IllegalArgumentException: X dimension > Y dimension".
240
We rotate based on IPP spec. */
241
new MediaSize(length, width, Size2DSyntax.INCH, msn);
242
}
243
}
244
}
245
246
// add to list of custom MediaSizeName
247
// for internal use of IPPPrintService
248
cupsCustomMediaSNames[i] = msn;
249
250
mpa = null;
251
try {
252
mpa = new MediaPrintableArea(x, y, w, h,
253
MediaPrintableArea.INCH);
254
} catch (IllegalArgumentException e) {
255
if (width > 0 && length > 0) {
256
mpa = new MediaPrintableArea(0, 0, width, length,
257
MediaPrintableArea.INCH);
258
}
259
}
260
cupsMediaPrintables[i] = mpa;
261
}
262
263
// initialize trays
264
cupsMediaTrays = new MediaTray[nTrays];
265
266
MediaTray mt;
267
for (int i=0; i<nTrays; i++) {
268
mt = new CustomMediaTray(media[(nPageSizes+i)*2],
269
media[(nPageSizes+i)*2+1]);
270
cupsMediaTrays[i] = mt;
271
}
272
273
}
274
275
/**
276
* Get CUPS default printer using IPP.
277
* Returns 2 values - index 0 is printer name, index 1 is the uri.
278
*/
279
static String[] getDefaultPrinter() {
280
// Try to get user/lpoptions-defined printer name from CUPS
281
// if not user-set, then go for server default destination
282
String[] printerInfo = new String[2];
283
printerInfo[0] = getCupsDefaultPrinter();
284
285
if (printerInfo[0] != null) {
286
printerInfo[1] = null;
287
return printerInfo.clone();
288
}
289
try {
290
URL url = new URL("http", getServer(), getPort(), "");
291
final HttpURLConnection urlConnection =
292
IPPPrintService.getIPPConnection(url);
293
294
if (urlConnection != null) {
295
OutputStream os = java.security.AccessController.
296
doPrivileged(new java.security.PrivilegedAction<OutputStream>() {
297
public OutputStream run() {
298
try {
299
return urlConnection.getOutputStream();
300
} catch (Exception e) {
301
IPPPrintService.debug_println(debugPrefix+e);
302
}
303
return null;
304
}
305
});
306
307
if (os == null) {
308
return null;
309
}
310
311
AttributeClass[] attCl = {
312
AttributeClass.ATTRIBUTES_CHARSET,
313
AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
314
new AttributeClass("requested-attributes",
315
AttributeClass.TAG_URI,
316
"printer-uri")
317
};
318
319
if (IPPPrintService.writeIPPRequest(os,
320
IPPPrintService.OP_CUPS_GET_DEFAULT,
321
attCl)) {
322
323
HashMap<String, AttributeClass> defaultMap = null;
324
325
InputStream is = urlConnection.getInputStream();
326
HashMap<String, AttributeClass>[] responseMap = IPPPrintService.readIPPResponse(
327
is);
328
is.close();
329
330
if (responseMap != null && responseMap.length > 0) {
331
defaultMap = responseMap[0];
332
} else {
333
IPPPrintService.debug_println(debugPrefix+
334
" empty response map for GET_DEFAULT.");
335
}
336
337
if (defaultMap == null) {
338
os.close();
339
urlConnection.disconnect();
340
341
/* CUPS on OS X, as initially configured, considers the
342
* default printer to be the last one used that's
343
* presently available. So if no default was
344
* reported, exec lpstat -d which has all the Apple
345
* special behaviour for this built in.
346
*/
347
if (PrintServiceLookupProvider.isMac()) {
348
printerInfo[0] = PrintServiceLookupProvider.
349
getDefaultPrinterNameSysV();
350
printerInfo[1] = null;
351
return printerInfo.clone();
352
} else {
353
return null;
354
}
355
}
356
357
358
AttributeClass attribClass = defaultMap.get("printer-name");
359
360
if (attribClass != null) {
361
printerInfo[0] = attribClass.getStringValue();
362
attribClass = defaultMap.get("printer-uri-supported");
363
IPPPrintService.debug_println(debugPrefix+
364
"printer-uri-supported="+attribClass);
365
if (attribClass != null) {
366
printerInfo[1] = attribClass.getStringValue();
367
} else {
368
printerInfo[1] = null;
369
}
370
os.close();
371
urlConnection.disconnect();
372
return printerInfo.clone();
373
}
374
}
375
os.close();
376
urlConnection.disconnect();
377
}
378
} catch (Exception e) {
379
}
380
return null;
381
}
382
383
384
/**
385
* Get list of all CUPS printers using IPP.
386
*/
387
static String[] getAllPrinters() {
388
389
if (getDomainSocketPathname() != null) {
390
String[] printerNames = getCupsDefaultPrinters();
391
if (printerNames != null && printerNames.length > 0) {
392
String[] printerURIs = new String[printerNames.length];
393
for (int i=0; i< printerNames.length; i++) {
394
printerURIs[i] = String.format("ipp://%s:%d/printers/%s",
395
getServer(), getPort(), printerNames[i]);
396
}
397
return printerURIs;
398
}
399
return null;
400
}
401
402
try {
403
URL url = new URL("http", getServer(), getPort(), "");
404
405
final HttpURLConnection urlConnection =
406
IPPPrintService.getIPPConnection(url);
407
408
if (urlConnection != null) {
409
OutputStream os = java.security.AccessController.
410
doPrivileged(new java.security.PrivilegedAction<OutputStream>() {
411
public OutputStream run() {
412
try {
413
return urlConnection.getOutputStream();
414
} catch (Exception e) {
415
}
416
return null;
417
}
418
});
419
420
if (os == null) {
421
return null;
422
}
423
424
AttributeClass[] attCl = {
425
AttributeClass.ATTRIBUTES_CHARSET,
426
AttributeClass.ATTRIBUTES_NATURAL_LANGUAGE,
427
new AttributeClass("requested-attributes",
428
AttributeClass.TAG_KEYWORD,
429
"printer-uri-supported")
430
};
431
432
if (IPPPrintService.writeIPPRequest(os,
433
IPPPrintService.OP_CUPS_GET_PRINTERS, attCl)) {
434
435
InputStream is = urlConnection.getInputStream();
436
HashMap<String, AttributeClass>[] responseMap =
437
IPPPrintService.readIPPResponse(is);
438
439
is.close();
440
os.close();
441
urlConnection.disconnect();
442
443
if (responseMap == null || responseMap.length == 0) {
444
return null;
445
}
446
447
ArrayList<String> printerNames = new ArrayList<>();
448
for (int i=0; i< responseMap.length; i++) {
449
AttributeClass attribClass =
450
responseMap[i].get("printer-uri-supported");
451
452
if (attribClass != null) {
453
String nameStr = attribClass.getStringValue();
454
printerNames.add(nameStr);
455
}
456
}
457
return printerNames.toArray(new String[] {});
458
} else {
459
os.close();
460
urlConnection.disconnect();
461
}
462
}
463
464
} catch (Exception e) {
465
}
466
return null;
467
468
}
469
470
/**
471
* Returns CUPS server name.
472
*/
473
public static String getServer() {
474
return cupsServer;
475
}
476
477
/**
478
* Returns CUPS port number.
479
*/
480
public static int getPort() {
481
return cupsPort;
482
}
483
484
/**
485
* Returns CUPS domain socket pathname.
486
*/
487
private static String getDomainSocketPathname() {
488
return domainSocketPathname;
489
}
490
491
@SuppressWarnings("removal")
492
private static boolean isSandboxedApp() {
493
if (PrintServiceLookupProvider.isMac()) {
494
return java.security.AccessController
495
.doPrivileged((java.security.PrivilegedAction<Boolean>) () ->
496
System.getenv("APP_SANDBOX_CONTAINER_ID") != null);
497
}
498
return false;
499
}
500
501
502
/**
503
* Detects if CUPS is running.
504
*/
505
public static boolean isCupsRunning() {
506
IPPPrintService.debug_println(debugPrefix+"libFound "+libFound);
507
if (libFound) {
508
String server = getDomainSocketPathname() != null
509
? getDomainSocketPathname()
510
: getServer();
511
IPPPrintService.debug_println(debugPrefix+"CUPS server "+server+
512
" port "+getPort()+
513
(getDomainSocketPathname() != null
514
? " use domain socket pathname"
515
: ""));
516
return canConnect(server, getPort());
517
} else {
518
return false;
519
}
520
}
521
522
523
}
524
525