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 // +1 is for storing the default media index 353 sizeArray = (*env)->NewFloatArray(env, option->num_choices*6+1); 354 if (sizeArray == NULL) { 355 unlink(filename); 356 j2d_ppdClose(ppd); 357 DPRINTF("CUPSfuncs::bad alloc new float array\n", "") 358 (*env)->ExceptionClear(env); 359 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); 360 return NULL; 361 } 362 363 dims = (*env)->GetFloatArrayElements(env, sizeArray, NULL); 364 if (dims == NULL) { 365 unlink(filename); 366 j2d_ppdClose(ppd); 367 (*env)->ExceptionClear(env); 368 JNU_ThrowOutOfMemoryError(env, "Could not create printer name"); 369 return NULL; 370 } 371 for (i = 0; i<option->num_choices; i++) { 372 choice = (option->choices)+i; 373 // get the index of the default page 374 if (!strcmp(choice->choice, option->defchoice)) { 375 dims[option->num_choices*6] = (float)i; 376 } 377 size = j2d_ppdPageSize(ppd, choice->choice); 378 if (size != NULL) { 379 // paper width and height 380 dims[i*6] = size->width; 381 dims[(i*6)+1] = size->length; 382 // paper printable area 383 dims[(i*6)+2] = size->left; 384 dims[(i*6)+3] = size->top; 385 dims[(i*6)+4] = size->right; 386 dims[(i*6)+5] = size->bottom; 387 } 388 } 389 390 (*env)->ReleaseFloatArrayElements(env, sizeArray, dims, 0); 391 } 392 393 j2d_ppdClose(ppd); 394 unlink(filename); 395 return sizeArray; 396 }