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