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 2010 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 papiAttributeListAddString(&job_attributes, PAPI_ATTR_EXCL, 379 "job-name", "standard input"); 380 381 /* create job request */ 382 populate_job_request(svc, &request, job_attributes, printer, 383 OPID_PRINT_JOB); 384 385 *stream = svc->connection; 386 387 result = ipp_send_initial_request_block(svc, request, 0); 388 papiAttributeListFree(request); 389 390 return (result); 391 } 392 393 papi_status_t 394 papiJobStreamWrite(papi_service_t handle, 395 papi_stream_t stream, void *buffer, size_t buflen) 396 { 397 papi_status_t result = PAPI_OK; 398 service_t *svc = handle; 399 size_t rc; 400 401 #ifdef DEBUG 402 printf("papiJobStreamWrite(0x%8.8x, 0x%8.8x, 0x%8.8x, %d)\n", 403 handle, stream, buffer, buflen); 404 httpDumpData(stdout, "papiJobStreamWrite:", buffer, buflen); 405 #endif 406 407 if ((svc == NULL) || (stream == NULL) || (buffer == NULL) || 408 (buflen == 0)) 409 return (PAPI_BAD_ARGUMENT); 410 411 while ((result == PAPI_OK) && (buflen > 0)) { 412 rc = ipp_request_write(svc, buffer, buflen); 413 if (rc < 0) 414 result = PAPI_TEMPORARY_ERROR; 415 else { 416 buffer = (char *)buffer + rc; 417 buflen -= rc; 418 } 419 } 420 421 #ifdef DEBUG 422 printf("papiJobStreamWrite(): %s\n", papiStatusString(result)); 423 #endif 424 425 return (result); 426 } 427 428 papi_status_t 429 papiJobStreamClose(papi_service_t handle, 430 papi_stream_t stream, papi_job_t *job) 431 { 432 papi_status_t result = PAPI_INTERNAL_ERROR; 433 http_status_t status = HTTP_CONTINUE; 434 service_t *svc = handle; 435 papi_attribute_t **response = NULL; 436 job_t *j = NULL; 437 438 if ((svc == NULL) || (stream == NULL) || (job == NULL)) 439 return (PAPI_BAD_ARGUMENT); 440 441 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 442 return (PAPI_TEMPORARY_ERROR); 443 444 (void) ipp_request_write(svc, "", 0); 445 446 /* update our connection info */ 447 while (status == HTTP_CONTINUE) 448 status = httpUpdate(svc->connection); 449 450 if (status != HTTP_OK) 451 return (http_to_papi_status(status)); 452 httpWait(svc->connection, 1000); 453 454 /* read the IPP response */ 455 result = ipp_read_message(&ipp_request_read, svc, &response, 456 IPP_TYPE_RESPONSE); 457 if (result == PAPI_OK) 458 result = ipp_status_info(svc, response); 459 460 if (result == PAPI_OK) { 461 papi_attribute_t **op = NULL; 462 463 papiAttributeListGetCollection(response, NULL, 464 "job-attributes-group", &op); 465 copy_attributes(&j->attributes, op); 466 } 467 papiAttributeListFree(response); 468 469 return (result); 470 } 471 472 papi_status_t 473 papiJobQuery(papi_service_t handle, char *printer, int32_t job_id, 474 char **requested_attrs, 475 papi_job_t *job) 476 { 477 papi_status_t result = PAPI_INTERNAL_ERROR; 478 service_t *svc = handle; 479 job_t *j = NULL; 480 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 481 482 if ((svc == NULL) || (printer == NULL)) 483 return (PAPI_BAD_ARGUMENT); 484 485 /* if we are already connected, use that connection. */ 486 if (svc->connection == NULL) 487 if ((result = service_connect(svc, printer)) != PAPI_OK) 488 return (result); 489 490 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 491 return (PAPI_TEMPORARY_ERROR); 492 493 ipp_initialize_request(svc, &request, OPID_GET_JOB_ATTRIBUTES); 494 495 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 496 497 if (requested_attrs != NULL) { 498 int i; 499 500 for (i = 0; requested_attrs[i] != NULL; i++) 501 papiAttributeListAddString(&op, PAPI_ATTR_APPEND, 502 "requested-attributes", requested_attrs[i]); 503 } 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 511 op = NULL; 512 papiAttributeListGetCollection(response, NULL, 513 "job-attributes-group", &op); 514 copy_attributes(&j->attributes, op); 515 papiAttributeListFree(response); 516 517 return (result); 518 } 519 520 /* papiJob{Cancel|Hold|Release|Restart|Promote} are all the same */ 521 static papi_status_t 522 _job_cancel_hold_release_restart_promote(papi_service_t handle, 523 char *printer, int32_t job_id, uint16_t type) 524 { 525 papi_status_t result = PAPI_INTERNAL_ERROR; 526 service_t *svc = handle; 527 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 528 529 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 530 return (PAPI_BAD_ARGUMENT); 531 532 /* if we are already connected, use that connection. */ 533 if (svc->connection == NULL) 534 if ((result = service_connect(svc, printer)) != PAPI_OK) 535 return (result); 536 537 ipp_initialize_request(svc, &request, type); 538 539 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 540 541 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 542 "operational-attributes-group", op); 543 papiAttributeListFree(op); 544 result = ipp_send_request(svc, request, &response); 545 papiAttributeListFree(request); 546 papiAttributeListFree(response); 547 548 return (result); 549 } 550 551 papi_status_t 552 papiJobCancel(papi_service_t handle, char *printer, int32_t job_id) 553 { 554 return (_job_cancel_hold_release_restart_promote(handle, printer, 555 job_id, OPID_CANCEL_JOB)); 556 } 557 558 559 papi_status_t 560 papiJobHold(papi_service_t handle, char *printer, int32_t job_id) 561 { 562 return (_job_cancel_hold_release_restart_promote(handle, printer, 563 job_id, OPID_HOLD_JOB)); 564 } 565 566 papi_status_t 567 papiJobRelease(papi_service_t handle, char *printer, int32_t job_id) 568 { 569 return (_job_cancel_hold_release_restart_promote(handle, printer, 570 job_id, OPID_RELEASE_JOB)); 571 } 572 573 papi_status_t 574 papiJobRestart(papi_service_t handle, char *printer, int32_t job_id) 575 { 576 return (_job_cancel_hold_release_restart_promote(handle, printer, 577 job_id, OPID_RESTART_JOB)); 578 } 579 580 papi_status_t 581 papiJobPromote(papi_service_t handle, char *printer, int32_t job_id) 582 { 583 return (_job_cancel_hold_release_restart_promote(handle, printer, 584 job_id, OPID_PROMOTE_JOB)); 585 } 586 587 papi_status_t 588 papiJobMove(papi_service_t handle, char *printer, int32_t job_id, 589 char *destination) 590 { 591 papi_status_t result = PAPI_INTERNAL_ERROR; 592 service_t *svc = handle; 593 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 594 595 if ((svc == NULL) || (printer == NULL) || (job_id < 0) || 596 (destination == NULL)) 597 return (PAPI_BAD_ARGUMENT); 598 599 /* if we are already connected, use that connection. */ 600 if (svc->connection == NULL) 601 if ((result = service_connect(svc, printer)) != PAPI_OK) 602 return (result); 603 604 ipp_initialize_request(svc, &request, OPID_CUPS_MOVE_JOB); 605 606 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 607 608 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 609 "operational-attributes-group", op); 610 papiAttributeListFree(op); 611 612 op = NULL; 613 papiAttributeListAddString(&op, PAPI_ATTR_EXCL, 614 "job-printer-uri", destination); 615 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 616 "job-attributes-group", op); 617 papiAttributeListFree(op); 618 619 result = ipp_send_request(svc, request, &response); 620 papiAttributeListFree(request); 621 papiAttributeListFree(response); 622 623 return (result); 624 } 625 626 papi_status_t 627 papiJobModify(papi_service_t handle, char *printer, int32_t job_id, 628 papi_attribute_t **attributes, papi_job_t *job) 629 { 630 papi_status_t result = PAPI_INTERNAL_ERROR; 631 service_t *svc = handle; 632 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 633 job_t *j = NULL; 634 635 if ((svc == NULL) || (printer == NULL) || (job_id < 0) || 636 (attributes == NULL)) 637 return (PAPI_BAD_ARGUMENT); 638 639 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 640 return (PAPI_TEMPORARY_ERROR); 641 642 /* if we are already connected, use that connection. */ 643 if (svc->connection == NULL) 644 if ((result = service_connect(svc, printer)) != PAPI_OK) 645 return (result); 646 647 ipp_initialize_request(svc, &request, OPID_SET_JOB_ATTRIBUTES); 648 649 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 650 651 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 652 "operational-attributes-group", op); 653 papiAttributeListFree(op); 654 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 655 "job-attributes-group", attributes); 656 result = ipp_send_request(svc, request, &response); 657 papiAttributeListFree(request); 658 659 op = NULL; 660 papiAttributeListGetCollection(response, NULL, 661 "job-attributes-group", &op); 662 copy_attributes(&j->attributes, op); 663 papiAttributeListFree(response); 664 665 return (result); 666 } 667