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 #include <jni.h>
27 #include <jni_util.h>
28 #include <jvm_md.h>
29 #include <dlfcn.h>
30 #include <cups/cups.h>
31 #include <cups/ppd.h>
32
33 //#define CUPS_DEBUG
34
35 #ifdef CUPS_DEBUG
36 #define DPRINTF(x, y) fprintf(stderr, x, y);
37 #else
38 #define DPRINTF(x, y)
39 #endif
40
41 typedef const char* (*fn_cupsServer)(void);
42 typedef int (*fn_ippPort)(void);
43 typedef http_t* (*fn_httpConnect)(const char *, int);
44 typedef void (*fn_httpClose)(http_t *);
45 typedef char* (*fn_cupsGetPPD)(const char *);
46 typedef ppd_file_t* (*fn_ppdOpenFile)(const char *);
47 typedef void (*fn_ppdClose)(ppd_file_t *);
48 typedef ppd_option_t* (*fn_ppdFindOption)(ppd_file_t *, const char *);
49 typedef ppd_size_t* (*fn_ppdPageSize)(ppd_file_t *, char *);
50
51 fn_cupsServer j2d_cupsServer;
52 fn_ippPort j2d_ippPort;
53 fn_httpConnect j2d_httpConnect;
54 fn_httpClose j2d_httpClose;
55 fn_cupsGetPPD j2d_cupsGetPPD;
56 fn_ppdOpenFile j2d_ppdOpenFile;
57 fn_ppdClose j2d_ppdClose;
58 fn_ppdFindOption j2d_ppdFindOption;
59 fn_ppdPageSize j2d_ppdPageSize;
60
61
62 /*
63 * Initialize library functions.
64 * // REMIND : move tab , add dlClose before return
65 */
66 JNIEXPORT jboolean JNICALL
67 Java_sun_print_CUPSPrinter_initIDs(JNIEnv *env,
68 jobject printObj) {
69 void *handle = dlopen(VERSIONED_JNI_LIB_NAME("cups", "2"),
70 RTLD_LAZY | RTLD_GLOBAL);
71
72 if (handle == NULL) {
73 handle = dlopen(JNI_LIB_NAME("cups"), RTLD_LAZY | RTLD_GLOBAL);
74 if (handle == NULL) {
75 return JNI_FALSE;
76 }
77 }
78
79 j2d_cupsServer = (fn_cupsServer)dlsym(handle, "cupsServer");
80 if (j2d_cupsServer == NULL) {
81 dlclose(handle);
82 return JNI_FALSE;
83 }
84
85 j2d_ippPort = (fn_ippPort)dlsym(handle, "ippPort");
86 if (j2d_ippPort == NULL) {
87 dlclose(handle);
88 return JNI_FALSE;
89 }
90
91 j2d_httpConnect = (fn_httpConnect)dlsym(handle, "httpConnect");
92 if (j2d_httpConnect == NULL) {
93 dlclose(handle);
94 return JNI_FALSE;
95 }
96
97 j2d_httpClose = (fn_httpClose)dlsym(handle, "httpClose");
98 if (j2d_httpClose == NULL) {
99 dlclose(handle);
100 return JNI_FALSE;
101 }
102
103 j2d_cupsGetPPD = (fn_cupsGetPPD)dlsym(handle, "cupsGetPPD");
104 if (j2d_cupsGetPPD == NULL) {
105 dlclose(handle);
106 return JNI_FALSE;
107 }
108
109 j2d_ppdOpenFile = (fn_ppdOpenFile)dlsym(handle, "ppdOpenFile");
110 if (j2d_ppdOpenFile == NULL) {
111 dlclose(handle);
112 return JNI_FALSE;
113
114 }
115
116 j2d_ppdClose = (fn_ppdClose)dlsym(handle, "ppdClose");
117 if (j2d_ppdClose == NULL) {
118 dlclose(handle);
119 return JNI_FALSE;
120
121 }
122
123 j2d_ppdFindOption = (fn_ppdFindOption)dlsym(handle, "ppdFindOption");
124 if (j2d_ppdFindOption == NULL) {
125 dlclose(handle);
126 return JNI_FALSE;
127 }
128
129 j2d_ppdPageSize = (fn_ppdPageSize)dlsym(handle, "ppdPageSize");
130 if (j2d_ppdPageSize == NULL) {
131 dlclose(handle);
132 return JNI_FALSE;
133 }
134
135 return JNI_TRUE;
136 }
137
138 /*
139 * Gets CUPS server name.
140 *
141 */
142 JNIEXPORT jstring JNICALL
143 Java_sun_print_CUPSPrinter_getCupsServer(JNIEnv *env,
144 jobject printObj)
145 {
146 jstring cServer = NULL;
147 const char* server = j2d_cupsServer();
148 if (server != NULL) {
149 // Is this a local domain socket?
150 if (strncmp(server, "/", 1) == 0) {
151 cServer = JNU_NewStringPlatform(env, "localhost");
152 } else {
153 cServer = JNU_NewStringPlatform(env, server);
154 }
155 }
156 return cServer;
157 }
158
159 /*
160 * Gets CUPS port name.
161 *
162 */
163 JNIEXPORT jint JNICALL
164 Java_sun_print_CUPSPrinter_getCupsPort(JNIEnv *env,
165 jobject printObj)
166 {
167 int port = j2d_ippPort();
168 return (jint) port;
169 }
170
171
172 /*
173 * Checks if connection can be made to the server.
174 *
175 */
176 JNIEXPORT jboolean JNICALL
177 Java_sun_print_CUPSPrinter_canConnect(JNIEnv *env,
178 jobject printObj,
179 jstring server,
180 jint port)
181 {
182 const char *serverName;
183 serverName = (*env)->GetStringUTFChars(env, server, NULL);
184 if (serverName != NULL) {
185 http_t *http = j2d_httpConnect(serverName, (int)port);
186 (*env)->ReleaseStringUTFChars(env, server, serverName);
187 if (http != NULL) {
188 j2d_httpClose(http);
189 return JNI_TRUE;
190 }
191 }
192 return JNI_FALSE;
193 }
194
195
196 /*
197 * Returns list of media: pages + trays
198 */
199 JNIEXPORT jobjectArray JNICALL
200 Java_sun_print_CUPSPrinter_getMedia(JNIEnv *env,
201 jobject printObj,
202 jstring printer)
203 {
204 ppd_file_t *ppd;
205 ppd_option_t *optionTray, *optionPage;
206 ppd_choice_t *choice;
207 const char *name;
208 const char *filename;
209 int i, nTrays=0, nPages=0, nTotal=0;
210 jstring utf_str;
211 jclass cls;
212 jobjectArray nameArray = NULL;
213
214 name = (*env)->GetStringUTFChars(env, printer, NULL);
215 if (name == NULL) {
216 (*env)->ExceptionClear(env);
217 JNU_ThrowOutOfMemoryError(env, "Could not create printer name");
218 return NULL;
219 }
220
221 // NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.
222 // unlink() must be caled to remove the file when finished using it.
223 filename = j2d_cupsGetPPD(name);
224 (*env)->ReleaseStringUTFChars(env, printer, name);
225 CHECK_NULL_RETURN(filename, NULL);
226
227 cls = (*env)->FindClass(env, "java/lang/String");
228 CHECK_NULL_RETURN(cls, NULL);
229
230 if ((ppd = j2d_ppdOpenFile(filename)) == NULL) {
231 unlink(filename);
232 DPRINTF("CUPSfuncs::unable to open PPD %s\n", filename);
233 return NULL;
234 }
235
236 optionPage = j2d_ppdFindOption(ppd, "PageSize");
237 if (optionPage != NULL) {
238 nPages = optionPage->num_choices;
239 }
240
241 optionTray = j2d_ppdFindOption(ppd, "InputSlot");
242 if (optionTray != NULL) {
243 nTrays = optionTray->num_choices;
244 }
245
246 if ((nTotal = (nPages+nTrays) *2) > 0) {
247 nameArray = (*env)->NewObjectArray(env, nTotal, cls, NULL);
248 if (nameArray == NULL) {
249 unlink(filename);
250 j2d_ppdClose(ppd);
251 DPRINTF("CUPSfuncs::bad alloc new array\n", "")
252 (*env)->ExceptionClear(env);
253 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
254 return NULL;
255 }
256
257 for (i = 0; optionPage!=NULL && i<nPages; i++) {
258 choice = (optionPage->choices)+i;
259 utf_str = JNU_NewStringPlatform(env, choice->text);
260 if (utf_str == NULL) {
261 unlink(filename);
262 j2d_ppdClose(ppd);
263 DPRINTF("CUPSfuncs::bad alloc new string ->text\n", "")
264 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
265 return NULL;
266 }
267 (*env)->SetObjectArrayElement(env, nameArray, i*2, utf_str);
268 (*env)->DeleteLocalRef(env, utf_str);
269 utf_str = JNU_NewStringPlatform(env, choice->choice);
270 if (utf_str == NULL) {
271 unlink(filename);
272 j2d_ppdClose(ppd);
273 DPRINTF("CUPSfuncs::bad alloc new string ->choice\n", "")
274 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
275 return NULL;
276 }
277 (*env)->SetObjectArrayElement(env, nameArray, i*2+1, utf_str);
278 (*env)->DeleteLocalRef(env, utf_str);
279 }
280
281 for (i = 0; optionTray!=NULL && i<nTrays; i++) {
282 choice = (optionTray->choices)+i;
283 utf_str = JNU_NewStringPlatform(env, choice->text);
284 if (utf_str == NULL) {
285 unlink(filename);
286 j2d_ppdClose(ppd);
287 DPRINTF("CUPSfuncs::bad alloc new string text\n", "")
288 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
289 return NULL;
290 }
291 (*env)->SetObjectArrayElement(env, nameArray,
292 (nPages+i)*2, utf_str);
293 (*env)->DeleteLocalRef(env, utf_str);
294 utf_str = JNU_NewStringPlatform(env, choice->choice);
295 if (utf_str == NULL) {
296 unlink(filename);
297 j2d_ppdClose(ppd);
298 DPRINTF("CUPSfuncs::bad alloc new string choice\n", "")
299 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
300 return NULL;
301 }
302 (*env)->SetObjectArrayElement(env, nameArray,
303 (nPages+i)*2+1, utf_str);
304 (*env)->DeleteLocalRef(env, utf_str);
305 }
306 }
307 j2d_ppdClose(ppd);
308 unlink(filename);
309 return nameArray;
310 }
311
312
313 /*
314 * Returns list of page sizes and imageable area.
315 */
316 JNIEXPORT jfloatArray JNICALL
317 Java_sun_print_CUPSPrinter_getPageSizes(JNIEnv *env,
318 jobject printObj,
319 jstring printer)
320 {
321 ppd_file_t *ppd;
322 ppd_option_t *option;
323 ppd_choice_t *choice;
324 ppd_size_t *size;
325
326 const char *name = (*env)->GetStringUTFChars(env, printer, NULL);
327 if (name == NULL) {
328 (*env)->ExceptionClear(env);
329 JNU_ThrowOutOfMemoryError(env, "Could not create printer name");
330 return NULL;
331 }
332 const char *filename;
333 int i;
334 jobjectArray sizeArray = NULL;
335 jfloat *dims;
336
337 // NOTE: cupsGetPPD returns a pointer to a filename of a temporary file.
338 // unlink() must be called to remove the file after using it.
339 filename = j2d_cupsGetPPD(name);
340 (*env)->ReleaseStringUTFChars(env, printer, name);
341 CHECK_NULL_RETURN(filename, NULL);
342 if ((ppd = j2d_ppdOpenFile(filename)) == NULL) {
343 unlink(filename);
344 DPRINTF("unable to open PPD %s\n", filename)
345 return NULL;
346 }
347 option = j2d_ppdFindOption(ppd, "PageSize");
348 if (option != NULL && option->num_choices > 0) {
349 // create array of dimensions - (num_choices * 6)
350 //to cover length & height
351 DPRINTF( "CUPSfuncs::option->num_choices %d\n", option->num_choices)
352 sizeArray = (*env)->NewFloatArray(env, option->num_choices*6);
353 if (sizeArray == NULL) {
354 unlink(filename);
355 j2d_ppdClose(ppd);
356 DPRINTF("CUPSfuncs::bad alloc new float array\n", "")
357 (*env)->ExceptionClear(env);
358 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
359 return NULL;
360 }
361
362 dims = (*env)->GetFloatArrayElements(env, sizeArray, NULL);
363 if (dims == NULL) {
364 unlink(filename);
365 j2d_ppdClose(ppd);
366 (*env)->ExceptionClear(env);
367 JNU_ThrowOutOfMemoryError(env, "Could not create printer name");
368 return NULL;
369 }
370 for (i = 0; i<option->num_choices; i++) {
371 choice = (option->choices)+i;
372 size = j2d_ppdPageSize(ppd, choice->choice);
373 if (size != NULL) {
374 // paper width and height
375 dims[i*6] = size->width;
376 dims[(i*6)+1] = size->length;
377 // paper printable area
378 dims[(i*6)+2] = size->left;
379 dims[(i*6)+3] = size->top;
380 dims[(i*6)+4] = size->right;
381 dims[(i*6)+5] = size->bottom;
382 }
383 }
384
385 (*env)->ReleaseFloatArrayElements(env, sizeArray, dims, 0);
386 }
387
388 j2d_ppdClose(ppd);
389 unlink(filename);
390 return sizeArray;
391 }
--- EOF ---