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