xref: /illumos-gate/usr/src/lib/print/libpapi-ipp/common/job.c (revision 355b4669e025ff377602b6fc7caaf30dbc218371)
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