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