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