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 /* create IPP request */ 276 populate_job_request(svc, &request, job_attributes, printer, req_type); 277 278 switch (req_type) { 279 case OPID_PRINT_JOB: 280 result = ipp_send_request_with_file(svc, request, &response, 281 files[0]); 282 break; 283 case OPID_CREATE_JOB: 284 case OPID_VALIDATE_JOB: 285 case OPID_PRINT_URI: 286 result = ipp_send_request(svc, request, &response); 287 break; 288 } 289 papiAttributeListFree(request); 290 291 if (result == PAPI_OK) { 292 papi_attribute_t **op = NULL; 293 294 /* retrieve the job attributes */ 295 papiAttributeListGetCollection(response, NULL, 296 "job-attributes-group", &op); 297 copy_attributes(&j->attributes, op); 298 299 if (req_type == OPID_CREATE_JOB) { 300 int32_t id = 0; 301 302 papiAttributeListGetInteger(j->attributes, NULL, 303 "job-id", &id); 304 /* send each document */ 305 for (i = 0; ((result == PAPI_OK) && (files[i] != NULL)); 306 i++) 307 result = send_document_uri(svc, files[i], 308 job_attributes, 309 printer, id, (files[i+1]?0:1), 310 data_type); 311 } 312 } 313 papiAttributeListFree(response); 314 315 return (result); 316 } 317 318 papi_status_t 319 papiJobSubmit(papi_service_t handle, char *printer, 320 papi_attribute_t **job_attributes, 321 papi_job_ticket_t *job_ticket, char **files, papi_job_t *job) 322 { 323 return (internal_job_submit(handle, printer, job_attributes, 324 job_ticket, files, job, _WITH_DATA)); 325 } 326 327 papi_status_t 328 papiJobSubmitByReference(papi_service_t handle, char *printer, 329 papi_attribute_t **job_attributes, 330 papi_job_ticket_t *job_ticket, char **files, papi_job_t *job) 331 { 332 return (internal_job_submit(handle, printer, job_attributes, 333 job_ticket, files, job, _BY_REFERENCE)); 334 } 335 336 papi_status_t 337 papiJobValidate(papi_service_t handle, char *printer, 338 papi_attribute_t **job_attributes, 339 papi_job_ticket_t *job_ticket, char **files, papi_job_t *job) 340 { 341 return (internal_job_submit(handle, printer, job_attributes, 342 job_ticket, files, job, _VALIDATE)); 343 } 344 345 papi_status_t 346 papiJobStreamOpen(papi_service_t handle, char *printer, 347 papi_attribute_t **job_attributes, 348 papi_job_ticket_t *job_ticket, papi_stream_t *stream) 349 { 350 papi_status_t result = PAPI_INTERNAL_ERROR; 351 papi_attribute_t **request = NULL; 352 service_t *svc = handle; 353 354 if ((svc == NULL) || (printer == NULL) || (stream == NULL)) 355 return (PAPI_BAD_ARGUMENT); 356 357 /* if we are already connected, use that connection. */ 358 if (svc->connection == NULL) 359 if ((result = service_connect(svc, printer)) != PAPI_OK) 360 return (result); 361 362 /* create job request */ 363 populate_job_request(svc, &request, job_attributes, printer, 364 OPID_PRINT_JOB); 365 366 *stream = svc->connection; 367 368 result = ipp_send_initial_request_block(svc, request, 0); 369 papiAttributeListFree(request); 370 371 return (result); 372 } 373 374 papi_status_t 375 papiJobStreamWrite(papi_service_t handle, 376 papi_stream_t stream, void *buffer, size_t buflen) 377 { 378 papi_status_t result = PAPI_OK; 379 service_t *svc = handle; 380 size_t rc; 381 382 #ifdef DEBUG 383 printf("papiJobStreamWrite(0x%8.8x, 0x%8.8x, 0x%8.8x, %d)\n", 384 handle, stream, buffer, buflen); 385 httpDumpData(stdout, "papiJobStreamWrite:", buffer, buflen); 386 #endif 387 388 if ((svc == NULL) || (stream == NULL) || (buffer == NULL) || 389 (buflen == 0)) 390 return (PAPI_BAD_ARGUMENT); 391 392 while ((result == PAPI_OK) && (buflen > 0)) { 393 rc = ipp_request_write(svc, buffer, buflen); 394 if (rc < 0) 395 result = PAPI_TEMPORARY_ERROR; 396 else { 397 buffer = (char *)buffer + rc; 398 buflen -= rc; 399 } 400 } 401 402 #ifdef DEBUG 403 printf("papiJobStreamWrite(): %s\n", papiStatusString(result)); 404 #endif 405 406 return (result); 407 } 408 409 papi_status_t 410 papiJobStreamClose(papi_service_t handle, 411 papi_stream_t stream, papi_job_t *job) 412 { 413 papi_status_t result = PAPI_INTERNAL_ERROR; 414 http_status_t status = HTTP_CONTINUE; 415 service_t *svc = handle; 416 papi_attribute_t **response = NULL; 417 job_t *j = NULL; 418 419 if ((svc == NULL) || (stream == NULL) || (job == NULL)) 420 return (PAPI_BAD_ARGUMENT); 421 422 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 423 return (PAPI_TEMPORARY_ERROR); 424 425 (void) ipp_request_write(svc, "", 0); 426 427 /* update our connection info */ 428 while (status == HTTP_CONTINUE) 429 status = httpUpdate(svc->connection); 430 431 if (status != HTTP_OK) 432 return (http_to_papi_status(status)); 433 httpWait(svc->connection, 1000); 434 435 /* read the IPP response */ 436 result = ipp_read_message(&ipp_request_read, svc, &response, 437 IPP_TYPE_RESPONSE); 438 if (result == PAPI_OK) 439 result = ipp_status_info(svc, response); 440 441 if (result == PAPI_OK) { 442 papi_attribute_t **op = NULL; 443 444 papiAttributeListGetCollection(response, NULL, 445 "job-attributes-group", &op); 446 copy_attributes(&j->attributes, op); 447 } 448 papiAttributeListFree(response); 449 450 return (result); 451 } 452 453 papi_status_t 454 papiJobQuery(papi_service_t handle, char *printer, int32_t job_id, 455 char **requested_attrs, 456 papi_job_t *job) 457 { 458 papi_status_t result = PAPI_INTERNAL_ERROR; 459 service_t *svc = handle; 460 job_t *j = NULL; 461 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 462 463 if ((svc == NULL) || (printer == NULL)) 464 return (PAPI_BAD_ARGUMENT); 465 466 /* if we are already connected, use that connection. */ 467 if (svc->connection == NULL) 468 if ((result = service_connect(svc, printer)) != PAPI_OK) 469 return (result); 470 471 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 472 return (PAPI_TEMPORARY_ERROR); 473 474 ipp_initialize_request(svc, &request, OPID_GET_JOB_ATTRIBUTES); 475 476 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 477 478 if (requested_attrs != NULL) { 479 int i; 480 481 for (i = 0; requested_attrs[i] != NULL; i++) 482 papiAttributeListAddString(&op, PAPI_ATTR_APPEND, 483 "requested-attributes", requested_attrs[i]); 484 } 485 486 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 487 "operational-attributes-group", op); 488 papiAttributeListFree(op); 489 result = ipp_send_request(svc, request, &response); 490 papiAttributeListFree(request); 491 492 op = NULL; 493 papiAttributeListGetCollection(response, NULL, 494 "job-attributes-group", &op); 495 copy_attributes(&j->attributes, op); 496 papiAttributeListFree(response); 497 498 return (result); 499 } 500 501 /* papiJob{Cancel|Hold|Release|Restart|Promote} are all the same */ 502 static papi_status_t 503 _job_cancel_hold_release_restart_promote(papi_service_t handle, 504 char *printer, int32_t job_id, uint16_t type) 505 { 506 papi_status_t result = PAPI_INTERNAL_ERROR; 507 service_t *svc = handle; 508 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 509 510 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 511 return (PAPI_BAD_ARGUMENT); 512 513 /* if we are already connected, use that connection. */ 514 if (svc->connection == NULL) 515 if ((result = service_connect(svc, printer)) != PAPI_OK) 516 return (result); 517 518 ipp_initialize_request(svc, &request, type); 519 520 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 521 522 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 523 "operational-attributes-group", op); 524 papiAttributeListFree(op); 525 result = ipp_send_request(svc, request, &response); 526 papiAttributeListFree(request); 527 papiAttributeListFree(response); 528 529 return (result); 530 } 531 532 papi_status_t 533 papiJobCancel(papi_service_t handle, char *printer, int32_t job_id) 534 { 535 return (_job_cancel_hold_release_restart_promote(handle, printer, 536 job_id, OPID_CANCEL_JOB)); 537 } 538 539 540 papi_status_t 541 papiJobHold(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_HOLD_JOB)); 545 } 546 547 papi_status_t 548 papiJobRelease(papi_service_t handle, char *printer, int32_t job_id) 549 { 550 return (_job_cancel_hold_release_restart_promote(handle, printer, 551 job_id, OPID_RELEASE_JOB)); 552 } 553 554 papi_status_t 555 papiJobRestart(papi_service_t handle, char *printer, int32_t job_id) 556 { 557 return (_job_cancel_hold_release_restart_promote(handle, printer, 558 job_id, OPID_RESTART_JOB)); 559 } 560 561 papi_status_t 562 papiJobPromote(papi_service_t handle, char *printer, int32_t job_id) 563 { 564 return (_job_cancel_hold_release_restart_promote(handle, printer, 565 job_id, OPID_PROMOTE_JOB)); 566 } 567 568 papi_status_t 569 papiJobMove(papi_service_t handle, char *printer, int32_t job_id, 570 char *destination) 571 { 572 papi_status_t result = PAPI_INTERNAL_ERROR; 573 service_t *svc = handle; 574 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 575 576 if ((svc == NULL) || (printer == NULL) || (job_id < 0) || 577 (destination == NULL)) 578 return (PAPI_BAD_ARGUMENT); 579 580 /* if we are already connected, use that connection. */ 581 if (svc->connection == NULL) 582 if ((result = service_connect(svc, printer)) != PAPI_OK) 583 return (result); 584 585 ipp_initialize_request(svc, &request, OPID_CUPS_MOVE_JOB); 586 587 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 588 589 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 590 "operational-attributes-group", op); 591 papiAttributeListFree(op); 592 593 op = NULL; 594 papiAttributeListAddString(&op, PAPI_ATTR_EXCL, 595 "job-printer-uri", destination); 596 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 597 "job-attributes-group", op); 598 papiAttributeListFree(op); 599 600 result = ipp_send_request(svc, request, &response); 601 papiAttributeListFree(request); 602 papiAttributeListFree(response); 603 604 return (result); 605 } 606 607 papi_status_t 608 papiJobModify(papi_service_t handle, char *printer, int32_t job_id, 609 papi_attribute_t **attributes, papi_job_t *job) 610 { 611 papi_status_t result = PAPI_INTERNAL_ERROR; 612 service_t *svc = handle; 613 papi_attribute_t **request = NULL, **op = NULL, **response = NULL; 614 job_t *j = NULL; 615 616 if ((svc == NULL) || (printer == NULL) || (job_id < 0) || 617 (attributes == NULL)) 618 return (PAPI_BAD_ARGUMENT); 619 620 if ((*job = j = calloc(1, sizeof (*j))) == NULL) 621 return (PAPI_TEMPORARY_ERROR); 622 623 /* if we are already connected, use that connection. */ 624 if (svc->connection == NULL) 625 if ((result = service_connect(svc, printer)) != PAPI_OK) 626 return (result); 627 628 ipp_initialize_request(svc, &request, OPID_SET_JOB_ATTRIBUTES); 629 630 ipp_initialize_operational_attributes(svc, &op, printer, job_id); 631 632 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 633 "operational-attributes-group", op); 634 papiAttributeListFree(op); 635 papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE, 636 "job-attributes-group", attributes); 637 result = ipp_send_request(svc, request, &response); 638 papiAttributeListFree(request); 639 640 op = NULL; 641 papiAttributeListGetCollection(response, NULL, 642 "job-attributes-group", &op); 643 copy_attributes(&j->attributes, op); 644 papiAttributeListFree(response); 645 646 return (result); 647 } 648