1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 */ 27 28 /* $Id: job.c 148 2006-04-25 16:54:17Z njacobs $ */ 29 30 31 /*LINTLIBRARY*/ 32 33 #include <stdlib.h> 34 #include <errno.h> 35 #include <string.h> 36 #include <papi_impl.h> 37 #include <fcntl.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 41 #ifndef OPID_CUPS_MOVE_JOB 42 #define OPID_CUPS_MOVE_JOB 0x400D 43 #endif 44 45 void 46 papiJobFree(papi_job_t job) 47 { 48 job_t *tmp = (job_t *)job; 49 50 if (tmp != NULL) { 51 if (tmp->attributes != NULL) 52 papiAttributeListFree(tmp->attributes); 53 free(tmp); 54 } 55 } 56 57 void 58 papiJobListFree(papi_job_t *jobs) 59 { 60 if (jobs != NULL) { 61 int i; 62 63 for (i = 0; jobs[i] != NULL; i++) 64 papiJobFree(jobs[i]); 65 free(jobs); 66 } 67 } 68 69 papi_attribute_t ** 70 papiJobGetAttributeList(papi_job_t job) 71 { 72 papi_attribute_t **result = NULL; 73 job_t *j = job; 74 75 if (j != NULL) 76 result = j->attributes; 77 78 return (result); 79 } 80 81 char * 82 papiJobGetPrinterName(papi_job_t job) 83 { 84 char *result = NULL; 85 job_t *j = job; 86 87 if (j != NULL) 88 (void) papiAttributeListGetString(j->attributes, NULL, 89 "printer-name", &result); 90 91 return (result); 92 } 93 94 int32_t 95 papiJobGetId(papi_job_t job) 96 { 97 int32_t result = -1; 98 job_t *j = job; 99 100 if (j != NULL) 101 (void) papiAttributeListGetInteger(j->attributes, NULL, 102 "job-id", &result); 103 104 return (result); 105 } 106 107 papi_job_ticket_t * 108 papiJobGetJobTicket(papi_job_t job) 109 { 110 papi_job_ticket_t *result = NULL; 111 112 return (result); 113 } 114 115 static void 116 populate_job_request(service_t *svc, papi_attribute_t ***request, 117 papi_attribute_t **attributes, char *printer, uint16_t type) 118 { 119 papi_attribute_t **operational = NULL, **job = NULL; 120 static char *operational_names[] = { 121 "job-name", "ipp-attribute-fidelity", "document-name", 122 "compression", "document-format", "document-natural-language", 123 "job-k-octets", "job-impressions", "job-media-sheets", NULL 124 }; 125 126 /* create the base IPP request */ 127 ipp_initialize_request(svc, request, type); 128 129 /* create an operational attributes group */ 130 ipp_initialize_operational_attributes(svc, &operational, printer, -1); 131 132 /* split up the attributes into operational and job attributes */ 133 split_and_copy_attributes(operational_names, attributes, 134 &operational, &job); 135 136 /* add the operational attributes group to the request */ 137 papiAttributeListAddCollection(request, PAPI_ATTR_REPLACE, 138 "operational-attributes-group", operational); 139 papiAttributeListFree(operational); 140 141 /* add the job attributes group to the request */ 142 if (job != NULL) { 143 papiAttributeListAddCollection(request, PAPI_ATTR_REPLACE, 144 "job-attributes-group", job); 145 papiAttributeListFree(job); 146 } 147 } 148 149 static papi_status_t 150 send_document_uri(service_t *svc, char *file, papi_attribute_t **attributes, 151 char *printer, int32_t id, char last, uint16_t type) 152 { 153 papi_status_t result = PAPI_INTERNAL_ERROR; 154 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 155 156 /* create the base IPP request */ 157 ipp_initialize_request(svc, &request, type); 158 159 /* create an operational attributes group */ 160 ipp_initialize_operational_attributes(svc, &op, printer, id); 161 162 papiAttributeListAddString(&op, PAPI_ATTR_REPLACE, "document-name", 163 file); 164 papiAttributeListAddBoolean(&op, PAPI_ATTR_REPLACE, "last-document", 165 (last ? PAPI_TRUE : PAPI_FALSE)); 166 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 167 "operational-attributes-group", op); 168 papiAttributeListFree(op); 169 170 /* send the IPP request to the server */ 171 result = ipp_send_request_with_file(svc, request, &response, file); 172 papiAttributeListFree(request); 173 papiAttributeListFree(response); 174 175 return (result); 176 } 177 178 typedef enum {_WITH_DATA, _BY_REFERENCE, _VALIDATE} call_type_t; 179 180 papi_status_t 181 internal_job_submit(papi_service_t handle, char *printer, 182 papi_attribute_t **job_attributes, 183 papi_job_ticket_t *job_ticket, 184 char **files, papi_job_t *job, 185 call_type_t call_type) 186 { 187 papi_status_t result = PAPI_INTERNAL_ERROR; 188 service_t *svc = handle; 189 struct stat statbuf; 190 job_t *j = NULL; 191 int i; 192 uint16_t req_type = OPID_PRINT_JOB; 193 uint16_t data_type = OPID_SEND_DOCUMENT; 194 papi_attribute_t **request = NULL, **response = NULL; 195 196 if ((svc == NULL) || (printer == NULL) || (job == NULL)) 197 return (PAPI_BAD_ARGUMENT); 198 199 switch (call_type) { 200 case _BY_REFERENCE: 201 #ifdef SOME_DAY_WE_WILL_BE_ABLE_TO_USE_URIS_FOR_JOB_DATA 202 /* 203 * For the time being, this is disabled. There are a number 204 * of issues to be dealt with before we can send a URI 205 * across the network to the server. For example, the file 206 * name(s) passed in are most likely relative to the current 207 * hosts filesystem. They also most likely will require some 208 * form of authentication information to be passed with the 209 * URI. 210 */ 211 req_type = OPID_PRINT_URI; 212 req_type = OPID_SEND_URI; 213 #endif 214 /* fall-through */ 215 case _WITH_DATA: 216 if ((files == NULL) || (files[0] == NULL)) 217 return (PAPI_BAD_ARGUMENT); 218 219 if (files[1] != NULL) /* more than 1 file */ 220 req_type = OPID_CREATE_JOB; 221 222 break; 223 case _VALIDATE: 224 req_type = OPID_VALIDATE_JOB; 225 /* if we have files, validate access to them */ 226 if (files != NULL) { 227 for (i = 0; files[i] != NULL; i++) { 228 if (access(files[i], R_OK) < 0) { 229 detailed_error(svc, "%s: %s", files[i], 230 strerror(errno)); 231 return (PAPI_DOCUMENT_ACCESS_ERROR); 232 } 233 234 if (strcmp("standard input", files[i]) != 0) { 235 stat(files[i], &statbuf); 236 if (statbuf.st_size == 0) { 237 detailed_error(svc, 238 "Zero byte (empty) file: " 239 "%s", 240 files[i]); 241 return (PAPI_BAD_ARGUMENT); 242 } 243 } 244 } 245 files = NULL; 246 } 247 break; 248 } 249 250 /* if we are already connected, use that connection. */ 251 if (svc->connection == NULL) 252 if ((result = service_connect(svc, printer)) != PAPI_OK) 253 return (result); 254 255 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 256 return (PAPI_TEMPORARY_ERROR); 257 258 /* create IPP request */ 259 populate_job_request(svc, &request, job_attributes, printer, req_type); 260 261 switch (req_type) { 262 case OPID_PRINT_JOB: 263 result = ipp_send_request_with_file(svc, request, &response, 264 files[0]); 265 break; 266 case OPID_CREATE_JOB: 267 case OPID_VALIDATE_JOB: 268 case OPID_PRINT_URI: 269 result = ipp_send_request(svc, request, &response); 270 break; 271 } 272 papiAttributeListFree(request); 273 274 if (result == PAPI_OK) { 275 papi_attribute_t **op = NULL; 276 277 /* retrieve the job attributes */ 278 papiAttributeListGetCollection(response, NULL, 279 "job-attributes-group", &op); 280 copy_attributes(&j->attributes, op); 281 282 if (req_type == OPID_CREATE_JOB) { 283 int32_t id = 0; 284 285 papiAttributeListGetInteger(j->attributes, NULL, 286 "job-id", &id); 287 /* send each document */ 288 for (i = 0; ((result == PAPI_OK) && (files[i] != NULL)); 289 i++) 290 result = send_document_uri(svc, files[i], 291 job_attributes, 292 printer, id, (files[i+1]?0:1), 293 data_type); 294 } 295 } 296 papiAttributeListFree(response); 297 298 return (result); 299 } 300 301 papi_status_t 302 papiJobSubmit(papi_service_t handle, char *printer, 303 papi_attribute_t **job_attributes, 304 papi_job_ticket_t *job_ticket, char **files, papi_job_t *job) 305 { 306 return (internal_job_submit(handle, printer, job_attributes, 307 job_ticket, files, job, _WITH_DATA)); 308 } 309 310 papi_status_t 311 papiJobSubmitByReference(papi_service_t handle, char *printer, 312 papi_attribute_t **job_attributes, 313 papi_job_ticket_t *job_ticket, char **files, papi_job_t *job) 314 { 315 return (internal_job_submit(handle, printer, job_attributes, 316 job_ticket, files, job, _BY_REFERENCE)); 317 } 318 319 papi_status_t 320 papiJobValidate(papi_service_t handle, char *printer, 321 papi_attribute_t **job_attributes, 322 papi_job_ticket_t *job_ticket, char **files, papi_job_t *job) 323 { 324 return (internal_job_submit(handle, printer, job_attributes, 325 job_ticket, files, job, _VALIDATE)); 326 } 327 328 papi_status_t 329 papiJobStreamOpen(papi_service_t handle, char *printer, 330 papi_attribute_t **job_attributes, 331 papi_job_ticket_t *job_ticket, papi_stream_t *stream) 332 { 333 papi_status_t result = PAPI_INTERNAL_ERROR; 334 papi_attribute_t **request = NULL; 335 service_t *svc = handle; 336 337 if ((svc == NULL) || (printer == NULL) || (stream == NULL)) 338 return (PAPI_BAD_ARGUMENT); 339 340 /* if we are already connected, use that connection. */ 341 if (svc->connection == NULL) 342 if ((result = service_connect(svc, printer)) != PAPI_OK) 343 return (result); 344 345 /* create job request */ 346 populate_job_request(svc, &request, job_attributes, printer, 347 OPID_PRINT_JOB); 348 349 *stream = svc->connection; 350 351 result = ipp_send_initial_request_block(svc, request, 0); 352 papiAttributeListFree(request); 353 354 return (result); 355 } 356 357 papi_status_t 358 papiJobStreamWrite(papi_service_t handle, 359 papi_stream_t stream, void *buffer, size_t buflen) 360 { 361 papi_status_t result = PAPI_OK; 362 service_t *svc = handle; 363 size_t rc; 364 365 #ifdef DEBUG 366 printf("papiJobStreamWrite(0x%8.8x, 0x%8.8x, 0x%8.8x, %d)\n", 367 handle, stream, buffer, buflen); 368 httpDumpData(stdout, "papiJobStreamWrite:", buffer, buflen); 369 #endif 370 371 if ((svc == NULL) || (stream == NULL) || (buffer == NULL) || 372 (buflen == 0)) 373 return (PAPI_BAD_ARGUMENT); 374 375 while ((result == PAPI_OK) && (buflen > 0)) { 376 rc = ipp_request_write(svc, buffer, buflen); 377 if (rc < 0) 378 result = PAPI_TEMPORARY_ERROR; 379 else { 380 buffer = (char *)buffer + rc; 381 buflen -= rc; 382 } 383 } 384 385 #ifdef DEBUG 386 printf("papiJobStreamWrite(): %s\n", papiStatusString(result)); 387 #endif 388 389 return (result); 390 } 391 392 papi_status_t 393 papiJobStreamClose(papi_service_t handle, 394 papi_stream_t stream, papi_job_t *job) 395 { 396 papi_status_t result = PAPI_INTERNAL_ERROR; 397 http_status_t status = HTTP_CONTINUE; 398 service_t *svc = handle; 399 papi_attribute_t **response = NULL; 400 job_t *j = NULL; 401 402 if ((svc == NULL) || (stream == NULL) || (job == NULL)) 403 return (PAPI_BAD_ARGUMENT); 404 405 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 406 return (PAPI_TEMPORARY_ERROR); 407 408 (void) ipp_request_write(svc, "", 0); 409 410 /* update our connection info */ 411 while (status == HTTP_CONTINUE) 412 status = httpUpdate(svc->connection); 413 414 if (status != HTTP_OK) 415 return (http_to_papi_status(status)); 416 httpWait(svc->connection, 1000); 417 418 /* read the IPP response */ 419 result = ipp_read_message(&ipp_request_read, svc, &response, 420 IPP_TYPE_RESPONSE); 421 if (result == PAPI_OK) 422 result = ipp_status_info(svc, response); 423 424 if (result == PAPI_OK) { 425 papi_attribute_t **op = NULL; 426 427 papiAttributeListGetCollection(response, NULL, 428 "job-attributes-group", &op); 429 copy_attributes(&j->attributes, op); 430 } 431 papiAttributeListFree(response); 432 433 return (result); 434 } 435 436 papi_status_t 437 papiJobQuery(papi_service_t handle, char *printer, int32_t job_id, 438 char **requested_attrs, 439 papi_job_t *job) 440 { 441 papi_status_t result = PAPI_INTERNAL_ERROR; 442 service_t *svc = handle; 443 job_t *j = NULL; 444 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 445 446 if ((svc == NULL) || (printer == NULL)) 447 return (PAPI_BAD_ARGUMENT); 448 449 /* if we are already connected, use that connection. */ 450 if (svc->connection == NULL) 451 if ((result = service_connect(svc, printer)) != PAPI_OK) 452 return (result); 453 454 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 455 return (PAPI_TEMPORARY_ERROR); 456 457 ipp_initialize_request(svc, &request, OPID_GET_JOB_ATTRIBUTES); 458 459 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 460 461 if (requested_attrs != NULL) { 462 int i; 463 464 for (i = 0; requested_attrs[i] != NULL; i++) 465 papiAttributeListAddString(&op, PAPI_ATTR_APPEND, 466 "requested-attributes", requested_attrs[i]); 467 } 468 469 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 470 "operational-attributes-group", op); 471 papiAttributeListFree(op); 472 result = ipp_send_request(svc, request, &response); 473 papiAttributeListFree(request); 474 475 op = NULL; 476 papiAttributeListGetCollection(response, NULL, 477 "job-attributes-group", &op); 478 copy_attributes(&j->attributes, op); 479 papiAttributeListFree(response); 480 481 return (result); 482 } 483 484 /* papiJob{Cancel|Hold|Release|Restart|Promote} are all the same */ 485 static papi_status_t 486 _job_cancel_hold_release_restart_promote(papi_service_t handle, 487 char *printer, int32_t job_id, uint16_t type) 488 { 489 papi_status_t result = PAPI_INTERNAL_ERROR; 490 service_t *svc = handle; 491 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 492 493 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 494 return (PAPI_BAD_ARGUMENT); 495 496 /* if we are already connected, use that connection. */ 497 if (svc->connection == NULL) 498 if ((result = service_connect(svc, printer)) != PAPI_OK) 499 return (result); 500 501 ipp_initialize_request(svc, &request, type); 502 503 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 504 505 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 506 "operational-attributes-group", op); 507 papiAttributeListFree(op); 508 result = ipp_send_request(svc, request, &response); 509 papiAttributeListFree(request); 510 papiAttributeListFree(response); 511 512 return (result); 513 } 514 515 papi_status_t 516 papiJobCancel(papi_service_t handle, char *printer, int32_t job_id) 517 { 518 return (_job_cancel_hold_release_restart_promote(handle, printer, 519 job_id, OPID_CANCEL_JOB)); 520 } 521 522 523 papi_status_t 524 papiJobHold(papi_service_t handle, char *printer, int32_t job_id) 525 { 526 return (_job_cancel_hold_release_restart_promote(handle, printer, 527 job_id, OPID_HOLD_JOB)); 528 } 529 530 papi_status_t 531 papiJobRelease(papi_service_t handle, char *printer, int32_t job_id) 532 { 533 return (_job_cancel_hold_release_restart_promote(handle, printer, 534 job_id, OPID_RELEASE_JOB)); 535 } 536 537 papi_status_t 538 papiJobRestart(papi_service_t handle, char *printer, int32_t job_id) 539 { 540 return (_job_cancel_hold_release_restart_promote(handle, printer, 541 job_id, OPID_RESTART_JOB)); 542 } 543 544 papi_status_t 545 papiJobPromote(papi_service_t handle, char *printer, int32_t job_id) 546 { 547 return (_job_cancel_hold_release_restart_promote(handle, printer, 548 job_id, OPID_PROMOTE_JOB)); 549 } 550 551 papi_status_t 552 papiJobMove(papi_service_t handle, char *printer, int32_t job_id, 553 char *destination) 554 { 555 papi_status_t result = PAPI_INTERNAL_ERROR; 556 service_t *svc = handle; 557 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 558 559 if ((svc == NULL) || (printer == NULL) || (job_id < 0) || 560 (destination == NULL)) 561 return (PAPI_BAD_ARGUMENT); 562 563 /* if we are already connected, use that connection. */ 564 if (svc->connection == NULL) 565 if ((result = service_connect(svc, printer)) != PAPI_OK) 566 return (result); 567 568 ipp_initialize_request(svc, &request, OPID_CUPS_MOVE_JOB); 569 570 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 571 572 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 573 "operational-attributes-group", op); 574 papiAttributeListFree(op); 575 576 op = NULL; 577 papiAttributeListAddString(&op, PAPI_ATTR_EXCL, 578 "job-printer-uri", destination); 579 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 580 "job-attributes-group", op); 581 papiAttributeListFree(op); 582 583 result = ipp_send_request(svc, request, &response); 584 papiAttributeListFree(request); 585 papiAttributeListFree(response); 586 587 return (result); 588 } 589 590 papi_status_t 591 papiJobModify(papi_service_t handle, char *printer, int32_t job_id, 592 papi_attribute_t **attributes, papi_job_t *job) 593 { 594 papi_status_t result = PAPI_INTERNAL_ERROR; 595 service_t *svc = handle; 596 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 597 job_t *j = NULL; 598 599 if ((svc == NULL) || (printer == NULL) || (job_id < 0) || 600 (attributes == NULL)) 601 return (PAPI_BAD_ARGUMENT); 602 603 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 604 return (PAPI_TEMPORARY_ERROR); 605 606 /* if we are already connected, use that connection. */ 607 if (svc->connection == NULL) 608 if ((result = service_connect(svc, printer)) != PAPI_OK) 609 return (result); 610 611 ipp_initialize_request(svc, &request, OPID_SET_JOB_ATTRIBUTES); 612 613 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 614 615 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 616 "operational-attributes-group", op); 617 papiAttributeListFree(op); 618 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 619 "job-attributes-group", attributes); 620 result = ipp_send_request(svc, request, &response); 621 papiAttributeListFree(request); 622 623 op = NULL; 624 papiAttributeListGetCollection(response, NULL, 625 "job-attributes-group", &op); 626 copy_attributes(&j->attributes, op); 627 papiAttributeListFree(response); 628 629 return (result); 630 } 631