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