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