12264Sjacobs /*
22264Sjacobs  * CDDL HEADER START
32264Sjacobs  *
42264Sjacobs  * The contents of this file are subject to the terms of the
52264Sjacobs  * Common Development and Distribution License (the "License").
62264Sjacobs  * You may not use this file except in compliance with the License.
72264Sjacobs  *
82264Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92264Sjacobs  * or http://www.opensolaris.org/os/licensing.
102264Sjacobs  * See the License for the specific language governing permissions
112264Sjacobs  * and limitations under the License.
122264Sjacobs  *
132264Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
142264Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152264Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
162264Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
172264Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
182264Sjacobs  *
192264Sjacobs  * CDDL HEADER END
202264Sjacobs  */
212264Sjacobs 
222264Sjacobs /*
238569SJonathan.Ca@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242264Sjacobs  * Use is subject to license terms.
252264Sjacobs  *
262264Sjacobs  */
272264Sjacobs 
282264Sjacobs /* $Id: job.c 148 2006-04-25 16:54:17Z njacobs $ */
292264Sjacobs 
302264Sjacobs 
312264Sjacobs /*LINTLIBRARY*/
322264Sjacobs 
332264Sjacobs #include <stdlib.h>
342264Sjacobs #include <errno.h>
352264Sjacobs #include <string.h>
362264Sjacobs #include <papi_impl.h>
378569SJonathan.Ca@Sun.COM #include <fcntl.h>
388569SJonathan.Ca@Sun.COM #include <sys/types.h>
398569SJonathan.Ca@Sun.COM #include <sys/stat.h>
40*9224SJonathan.Ca@Sun.COM #include <libintl.h>
412264Sjacobs 
422264Sjacobs #ifndef OPID_CUPS_MOVE_JOB
432264Sjacobs #define	OPID_CUPS_MOVE_JOB 0x400D
442264Sjacobs #endif
452264Sjacobs 
462264Sjacobs void
472264Sjacobs papiJobFree(papi_job_t job)
482264Sjacobs {
492264Sjacobs 	job_t *tmp = (job_t *)job;
502264Sjacobs 
512264Sjacobs 	if (tmp != NULL) {
522264Sjacobs 		if (tmp->attributes != NULL)
532264Sjacobs 			papiAttributeListFree(tmp->attributes);
542264Sjacobs 		free(tmp);
552264Sjacobs 	}
562264Sjacobs }
572264Sjacobs 
582264Sjacobs void
592264Sjacobs papiJobListFree(papi_job_t *jobs)
602264Sjacobs {
612264Sjacobs 	if (jobs != NULL) {
622264Sjacobs 		int i;
632264Sjacobs 
642264Sjacobs 		for (i = 0; jobs[i] != NULL; i++)
652264Sjacobs 			papiJobFree(jobs[i]);
662264Sjacobs 		free(jobs);
672264Sjacobs 	}
682264Sjacobs }
692264Sjacobs 
702264Sjacobs papi_attribute_t **
712264Sjacobs papiJobGetAttributeList(papi_job_t job)
722264Sjacobs {
732264Sjacobs 	papi_attribute_t **result = NULL;
742264Sjacobs 	job_t *j = job;
752264Sjacobs 
762264Sjacobs 	if (j != NULL)
772264Sjacobs 		result = j->attributes;
782264Sjacobs 
792264Sjacobs 	return (result);
802264Sjacobs }
812264Sjacobs 
822264Sjacobs char *
832264Sjacobs papiJobGetPrinterName(papi_job_t job)
842264Sjacobs {
852264Sjacobs 	char *result = NULL;
862264Sjacobs 	job_t *j = job;
872264Sjacobs 
882264Sjacobs 	if (j != NULL)
892264Sjacobs 		(void) papiAttributeListGetString(j->attributes, NULL,
908569SJonathan.Ca@Sun.COM 		    "printer-name", &result);
912264Sjacobs 
922264Sjacobs 	return (result);
932264Sjacobs }
942264Sjacobs 
952264Sjacobs int32_t
962264Sjacobs papiJobGetId(papi_job_t job)
972264Sjacobs {
982264Sjacobs 	int32_t result = -1;
992264Sjacobs 	job_t *j = job;
1002264Sjacobs 
1012264Sjacobs 	if (j != NULL)
1022264Sjacobs 		(void) papiAttributeListGetInteger(j->attributes, NULL,
1038569SJonathan.Ca@Sun.COM 		    "job-id", &result);
1042264Sjacobs 
1052264Sjacobs 	return (result);
1062264Sjacobs }
1072264Sjacobs 
1082264Sjacobs papi_job_ticket_t *
1092264Sjacobs papiJobGetJobTicket(papi_job_t job)
1102264Sjacobs {
1112264Sjacobs 	papi_job_ticket_t *result = NULL;
1122264Sjacobs 
1132264Sjacobs 	return (result);
1142264Sjacobs }
1152264Sjacobs 
1162264Sjacobs static void
1172264Sjacobs populate_job_request(service_t *svc, papi_attribute_t ***request,
1182264Sjacobs 		papi_attribute_t **attributes, char *printer, uint16_t type)
1192264Sjacobs {
1202264Sjacobs 	papi_attribute_t **operational = NULL, **job = NULL;
1212264Sjacobs 	static char *operational_names[] = {
1222264Sjacobs 		"job-name", "ipp-attribute-fidelity", "document-name",
1232264Sjacobs 		"compression", "document-format", "document-natural-language",
1242264Sjacobs 		"job-k-octets", "job-impressions", "job-media-sheets", NULL
1252264Sjacobs 	};
1262264Sjacobs 
1272264Sjacobs 	/* create the base IPP request */
1282264Sjacobs 	ipp_initialize_request(svc, request, type);
1292264Sjacobs 
1302264Sjacobs 	/* create an operational attributes group */
1313917Sjacobs 	ipp_initialize_operational_attributes(svc, &operational, printer, -1);
1322264Sjacobs 
1332264Sjacobs 	/* split up the attributes into operational and job attributes */
1342264Sjacobs 	split_and_copy_attributes(operational_names, attributes,
1358569SJonathan.Ca@Sun.COM 	    &operational, &job);
1362264Sjacobs 
1372264Sjacobs 	/* add the operational attributes group to the request */
1382264Sjacobs 	papiAttributeListAddCollection(request, PAPI_ATTR_REPLACE,
1398569SJonathan.Ca@Sun.COM 	    "operational-attributes-group", operational);
1402264Sjacobs 	papiAttributeListFree(operational);
1412264Sjacobs 
1422264Sjacobs 	/* add the job attributes group to the request */
1432264Sjacobs 	if (job != NULL) {
1449152SSonam.Gupta@Sun.COM 		/*
1459152SSonam.Gupta@Sun.COM 		 * Add job-originating-host-name to attributes
1469152SSonam.Gupta@Sun.COM 		 * if not already set.
1479152SSonam.Gupta@Sun.COM 		 */
1489152SSonam.Gupta@Sun.COM 		char *hostname = NULL;
1499152SSonam.Gupta@Sun.COM 
1509152SSonam.Gupta@Sun.COM 		papiAttributeListGetString(job, NULL,
1519152SSonam.Gupta@Sun.COM 		    "job-originating-host-name", &hostname);
1529152SSonam.Gupta@Sun.COM 
1539152SSonam.Gupta@Sun.COM 		if (hostname == NULL) {
1549152SSonam.Gupta@Sun.COM 			char host[BUFSIZ];
1559152SSonam.Gupta@Sun.COM 
1569152SSonam.Gupta@Sun.COM 			if (gethostname(host, sizeof (host)) == 0)
1579152SSonam.Gupta@Sun.COM 				papiAttributeListAddString(&job, PAPI_ATTR_EXCL,
1589152SSonam.Gupta@Sun.COM 				    "job-originating-host-name", host);
1599152SSonam.Gupta@Sun.COM 		}
1609152SSonam.Gupta@Sun.COM 
1612264Sjacobs 		papiAttributeListAddCollection(request, PAPI_ATTR_REPLACE,
1628569SJonathan.Ca@Sun.COM 		    "job-attributes-group", job);
1632264Sjacobs 		papiAttributeListFree(job);
1642264Sjacobs 	}
1652264Sjacobs }
1662264Sjacobs 
1672264Sjacobs static papi_status_t
1682264Sjacobs send_document_uri(service_t *svc, char *file, papi_attribute_t **attributes,
1692264Sjacobs 		char *printer, int32_t id, char last, uint16_t type)
1702264Sjacobs {
1712264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
1722264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
1732264Sjacobs 
1742264Sjacobs 	/* create the base IPP request */
1752264Sjacobs 	ipp_initialize_request(svc, &request, type);
1762264Sjacobs 
1772264Sjacobs 	/* create an operational attributes group */
1783917Sjacobs 	ipp_initialize_operational_attributes(svc, &op, printer, id);
1792264Sjacobs 
1802264Sjacobs 	papiAttributeListAddString(&op, PAPI_ATTR_REPLACE, "document-name",
1818569SJonathan.Ca@Sun.COM 	    file);
1822264Sjacobs 	papiAttributeListAddBoolean(&op, PAPI_ATTR_REPLACE, "last-document",
1838569SJonathan.Ca@Sun.COM 	    (last ? PAPI_TRUE : PAPI_FALSE));
1842264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
1858569SJonathan.Ca@Sun.COM 	    "operational-attributes-group", op);
1862264Sjacobs 	papiAttributeListFree(op);
1872264Sjacobs 
1882264Sjacobs 	/* send the IPP request to the server */
1892264Sjacobs 	result = ipp_send_request_with_file(svc, request, &response, file);
1902264Sjacobs 	papiAttributeListFree(request);
1912264Sjacobs 	papiAttributeListFree(response);
1922264Sjacobs 
1932264Sjacobs 	return (result);
1942264Sjacobs }
1952264Sjacobs 
1962264Sjacobs typedef enum {_WITH_DATA, _BY_REFERENCE, _VALIDATE} call_type_t;
1972264Sjacobs 
1982264Sjacobs papi_status_t
1992264Sjacobs internal_job_submit(papi_service_t handle, char *printer,
2002264Sjacobs 		papi_attribute_t **job_attributes,
2012264Sjacobs 		papi_job_ticket_t *job_ticket,
2022264Sjacobs 		char **files, papi_job_t *job,
2032264Sjacobs 		call_type_t call_type)
2042264Sjacobs {
2052264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
2062264Sjacobs 	service_t *svc = handle;
2078569SJonathan.Ca@Sun.COM 	struct stat statbuf;
2082264Sjacobs 	job_t *j = NULL;
2092264Sjacobs 	int i;
2102264Sjacobs 	uint16_t req_type = OPID_PRINT_JOB;
2112264Sjacobs 	uint16_t data_type = OPID_SEND_DOCUMENT;
2122264Sjacobs 	papi_attribute_t **request = NULL, **response = NULL;
2132264Sjacobs 
2142264Sjacobs 	if ((svc == NULL) || (printer == NULL) || (job == NULL))
2152264Sjacobs 		return (PAPI_BAD_ARGUMENT);
2162264Sjacobs 
2172264Sjacobs 	switch (call_type) {
2182264Sjacobs 	case _BY_REFERENCE:
2192264Sjacobs #ifdef SOME_DAY_WE_WILL_BE_ABLE_TO_USE_URIS_FOR_JOB_DATA
2202264Sjacobs 		/*
2212264Sjacobs 		 * For the time being, this is disabled.  There are a number
2222264Sjacobs 		 * of issues to be dealt with before we can send a URI
2232264Sjacobs 		 * across the network to the server.  For example, the file
2242264Sjacobs 		 * name(s) passed in are most likely relative to the current
2252264Sjacobs 		 * hosts filesystem.  They also most likely will require some
2262264Sjacobs 		 * form of authentication information to be passed with the
2272264Sjacobs 		 * URI.
2282264Sjacobs 		 */
2292264Sjacobs 		req_type = OPID_PRINT_URI;
2302264Sjacobs 		req_type = OPID_SEND_URI;
2312264Sjacobs #endif
2322264Sjacobs 		/* fall-through */
2332264Sjacobs 	case _WITH_DATA:
2342264Sjacobs 		if ((files == NULL) || (files[0] == NULL))
2352264Sjacobs 			return (PAPI_BAD_ARGUMENT);
2362264Sjacobs 
2372264Sjacobs 		if (files[1] != NULL)	/* more than 1 file */
2382264Sjacobs 			req_type = OPID_CREATE_JOB;
2392264Sjacobs 
2402264Sjacobs 		break;
2412264Sjacobs 	case _VALIDATE:
2422264Sjacobs 		req_type = OPID_VALIDATE_JOB;
2432264Sjacobs 		/* if we have files, validate access to them */
2442264Sjacobs 		if (files != NULL) {
2458569SJonathan.Ca@Sun.COM 			for (i = 0; files[i] != NULL; i++) {
2462264Sjacobs 				if (access(files[i], R_OK) < 0) {
2472264Sjacobs 					detailed_error(svc, "%s: %s", files[i],
2488569SJonathan.Ca@Sun.COM 					    strerror(errno));
2492264Sjacobs 					return (PAPI_DOCUMENT_ACCESS_ERROR);
2502264Sjacobs 				}
2518569SJonathan.Ca@Sun.COM 
2528569SJonathan.Ca@Sun.COM 				if (strcmp("standard input", files[i]) != 0) {
253*9224SJonathan.Ca@Sun.COM 					if (stat(files[i], &statbuf) < 0) {
254*9224SJonathan.Ca@Sun.COM 						detailed_error(svc, gettext(
255*9224SJonathan.Ca@Sun.COM 						    "Cannot access file: %s:"
256*9224SJonathan.Ca@Sun.COM 						    " %s"), files[i],
257*9224SJonathan.Ca@Sun.COM 						    strerror(errno));
258*9224SJonathan.Ca@Sun.COM 						return (
259*9224SJonathan.Ca@Sun.COM 						    PAPI_DOCUMENT_ACCESS_ERROR);
260*9224SJonathan.Ca@Sun.COM 					}
2618569SJonathan.Ca@Sun.COM 					if (statbuf.st_size == 0) {
2628569SJonathan.Ca@Sun.COM 						detailed_error(svc,
2638569SJonathan.Ca@Sun.COM 						    "Zero byte (empty) file: "
2648569SJonathan.Ca@Sun.COM 						    "%s",
2658569SJonathan.Ca@Sun.COM 						    files[i]);
2668569SJonathan.Ca@Sun.COM 						return (PAPI_BAD_ARGUMENT);
2678569SJonathan.Ca@Sun.COM 					}
2688569SJonathan.Ca@Sun.COM 				}
2698569SJonathan.Ca@Sun.COM 			}
2702264Sjacobs 			files = NULL;
2712264Sjacobs 		}
2722264Sjacobs 		break;
2732264Sjacobs 	}
2742264Sjacobs 
2752264Sjacobs 	/* if we are already connected, use that connection. */
2762264Sjacobs 	if (svc->connection == NULL)
2772264Sjacobs 		if ((result = service_connect(svc, printer)) != PAPI_OK)
2782264Sjacobs 			return (result);
2792264Sjacobs 
2802264Sjacobs 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
2812264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
2822264Sjacobs 
2839166SSonam.Gupta@Sun.COM 	/*
2849166SSonam.Gupta@Sun.COM 	 * before creating IPP request
2859166SSonam.Gupta@Sun.COM 	 * add the job-name
2869166SSonam.Gupta@Sun.COM 	 */
2879166SSonam.Gupta@Sun.COM 	if ((files != NULL) && (files[0] != NULL))
2889166SSonam.Gupta@Sun.COM 		papiAttributeListAddString(&job_attributes, PAPI_ATTR_EXCL,
2899166SSonam.Gupta@Sun.COM 		    "job-name", files[0]);
2909166SSonam.Gupta@Sun.COM 
2912264Sjacobs 	/* create IPP request */
2922264Sjacobs 	populate_job_request(svc, &request, job_attributes, printer, req_type);
2932264Sjacobs 
2942264Sjacobs 	switch (req_type) {
2952264Sjacobs 	case OPID_PRINT_JOB:
2962264Sjacobs 		result = ipp_send_request_with_file(svc, request, &response,
2978569SJonathan.Ca@Sun.COM 		    files[0]);
2982264Sjacobs 		break;
2992264Sjacobs 	case OPID_CREATE_JOB:
3002264Sjacobs 	case OPID_VALIDATE_JOB:
3012264Sjacobs 	case OPID_PRINT_URI:
3022264Sjacobs 		result = ipp_send_request(svc, request, &response);
3032264Sjacobs 		break;
3042264Sjacobs 	}
3052264Sjacobs 	papiAttributeListFree(request);
3062264Sjacobs 
3072264Sjacobs 	if (result == PAPI_OK) {
3082264Sjacobs 		papi_attribute_t **op = NULL;
3092264Sjacobs 
3102264Sjacobs 		/* retrieve the job attributes */
3112264Sjacobs 		papiAttributeListGetCollection(response, NULL,
3128569SJonathan.Ca@Sun.COM 		    "job-attributes-group", &op);
3132264Sjacobs 		copy_attributes(&j->attributes, op);
3142264Sjacobs 
3152264Sjacobs 		if (req_type == OPID_CREATE_JOB) {
3162264Sjacobs 			int32_t id = 0;
3172264Sjacobs 
3182264Sjacobs 			papiAttributeListGetInteger(j->attributes, NULL,
3198569SJonathan.Ca@Sun.COM 			    "job-id", &id);
3202264Sjacobs 			/* send each document */
3212264Sjacobs 			for (i = 0; ((result == PAPI_OK) && (files[i] != NULL));
3228569SJonathan.Ca@Sun.COM 			    i++)
3232264Sjacobs 				result = send_document_uri(svc, files[i],
3248569SJonathan.Ca@Sun.COM 				    job_attributes,
3258569SJonathan.Ca@Sun.COM 				    printer, id, (files[i+1]?0:1),
3268569SJonathan.Ca@Sun.COM 				    data_type);
3272264Sjacobs 		}
3282264Sjacobs 	}
3292264Sjacobs 	papiAttributeListFree(response);
3302264Sjacobs 
3312264Sjacobs 	return (result);
3322264Sjacobs }
3332264Sjacobs 
3342264Sjacobs papi_status_t
3352264Sjacobs papiJobSubmit(papi_service_t handle, char *printer,
3362264Sjacobs 		papi_attribute_t **job_attributes,
3372264Sjacobs 		papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
3382264Sjacobs {
3392264Sjacobs 	return (internal_job_submit(handle, printer, job_attributes,
3408569SJonathan.Ca@Sun.COM 	    job_ticket, files, job, _WITH_DATA));
3412264Sjacobs }
3422264Sjacobs 
3432264Sjacobs papi_status_t
3442264Sjacobs papiJobSubmitByReference(papi_service_t handle, char *printer,
3452264Sjacobs 		papi_attribute_t **job_attributes,
3462264Sjacobs 		papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
3472264Sjacobs {
3482264Sjacobs 	return (internal_job_submit(handle, printer, job_attributes,
3498569SJonathan.Ca@Sun.COM 	    job_ticket, files, job, _BY_REFERENCE));
3502264Sjacobs }
3512264Sjacobs 
3522264Sjacobs papi_status_t
3532264Sjacobs papiJobValidate(papi_service_t handle, char *printer,
3542264Sjacobs 		papi_attribute_t **job_attributes,
3552264Sjacobs 		papi_job_ticket_t *job_ticket, char **files, papi_job_t *job)
3562264Sjacobs {
3572264Sjacobs 	return (internal_job_submit(handle, printer, job_attributes,
3588569SJonathan.Ca@Sun.COM 	    job_ticket, files, job, _VALIDATE));
3592264Sjacobs }
3602264Sjacobs 
3612264Sjacobs papi_status_t
3622264Sjacobs papiJobStreamOpen(papi_service_t handle, char *printer,
3632264Sjacobs 		papi_attribute_t **job_attributes,
3642264Sjacobs 		papi_job_ticket_t *job_ticket, papi_stream_t *stream)
3652264Sjacobs {
3662264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
3672264Sjacobs 	papi_attribute_t **request = NULL;
3682264Sjacobs 	service_t *svc = handle;
3692264Sjacobs 
3702264Sjacobs 	if ((svc == NULL) || (printer == NULL) || (stream == NULL))
3712264Sjacobs 		return (PAPI_BAD_ARGUMENT);
3722264Sjacobs 
3732264Sjacobs 	/* if we are already connected, use that connection. */
3742264Sjacobs 	if (svc->connection == NULL)
3752264Sjacobs 		if ((result = service_connect(svc, printer)) != PAPI_OK)
3762264Sjacobs 			return (result);
3772264Sjacobs 
3782264Sjacobs 	/* create job request */
3792264Sjacobs 	populate_job_request(svc, &request, job_attributes, printer,
3808569SJonathan.Ca@Sun.COM 	    OPID_PRINT_JOB);
3812264Sjacobs 
3822264Sjacobs 	*stream = svc->connection;
3832264Sjacobs 
3842264Sjacobs 	result = ipp_send_initial_request_block(svc, request, 0);
3852264Sjacobs 	papiAttributeListFree(request);
3862264Sjacobs 
3872264Sjacobs 	return (result);
3882264Sjacobs }
3892264Sjacobs 
3902264Sjacobs papi_status_t
3912264Sjacobs papiJobStreamWrite(papi_service_t handle,
3922264Sjacobs 		papi_stream_t stream, void *buffer, size_t buflen)
3932264Sjacobs {
3942264Sjacobs 	papi_status_t result = PAPI_OK;
3952264Sjacobs 	service_t *svc = handle;
3962264Sjacobs 	size_t rc;
3972264Sjacobs 
3982264Sjacobs #ifdef DEBUG
3992264Sjacobs 	printf("papiJobStreamWrite(0x%8.8x, 0x%8.8x, 0x%8.8x, %d)\n",
4008569SJonathan.Ca@Sun.COM 	    handle, stream, buffer, buflen);
4012264Sjacobs 	httpDumpData(stdout, "papiJobStreamWrite:", buffer, buflen);
4022264Sjacobs #endif
4032264Sjacobs 
4042264Sjacobs 	if ((svc == NULL) || (stream == NULL) || (buffer == NULL) ||
4052264Sjacobs 	    (buflen == 0))
4062264Sjacobs 		return (PAPI_BAD_ARGUMENT);
4072264Sjacobs 
4082264Sjacobs 	while ((result == PAPI_OK) && (buflen > 0)) {
4092264Sjacobs 		rc = ipp_request_write(svc, buffer, buflen);
4102264Sjacobs 		if (rc < 0)
4112264Sjacobs 			result = PAPI_TEMPORARY_ERROR;
4122264Sjacobs 		else {
4132264Sjacobs 			buffer = (char *)buffer + rc;
4142264Sjacobs 			buflen -= rc;
4152264Sjacobs 		}
4162264Sjacobs 	}
4172264Sjacobs 
4182264Sjacobs #ifdef DEBUG
4192264Sjacobs 	printf("papiJobStreamWrite(): %s\n", papiStatusString(result));
4202264Sjacobs #endif
4212264Sjacobs 
4222264Sjacobs 	return (result);
4232264Sjacobs }
4242264Sjacobs 
4252264Sjacobs papi_status_t
4262264Sjacobs papiJobStreamClose(papi_service_t handle,
4272264Sjacobs 		papi_stream_t stream, papi_job_t *job)
4282264Sjacobs {
4292264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
4302264Sjacobs 	http_status_t status = HTTP_CONTINUE;
4312264Sjacobs 	service_t *svc = handle;
4322264Sjacobs 	papi_attribute_t **response = NULL;
4332264Sjacobs 	job_t *j = NULL;
4342264Sjacobs 
4352264Sjacobs 	if ((svc == NULL) || (stream == NULL) || (job == NULL))
4362264Sjacobs 		return (PAPI_BAD_ARGUMENT);
4372264Sjacobs 
4382264Sjacobs 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
4392264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
4402264Sjacobs 
4412264Sjacobs 	(void) ipp_request_write(svc, "", 0);
4422264Sjacobs 
4432264Sjacobs 	/* update our connection info */
4442264Sjacobs 	while (status == HTTP_CONTINUE)
4452264Sjacobs 		status = httpUpdate(svc->connection);
4462264Sjacobs 
4472264Sjacobs 	if (status != HTTP_OK)
4482264Sjacobs 		return (http_to_papi_status(status));
4492264Sjacobs 	httpWait(svc->connection, 1000);
4502264Sjacobs 
4512264Sjacobs 	/* read the IPP response */
4522264Sjacobs 	result = ipp_read_message(&ipp_request_read, svc, &response,
4538569SJonathan.Ca@Sun.COM 	    IPP_TYPE_RESPONSE);
4542264Sjacobs 	if (result == PAPI_OK)
4552264Sjacobs 		result = ipp_status_info(svc, response);
4562264Sjacobs 
4572264Sjacobs 	if (result == PAPI_OK) {
4582264Sjacobs 		papi_attribute_t **op = NULL;
4592264Sjacobs 
4602264Sjacobs 		papiAttributeListGetCollection(response, NULL,
4618569SJonathan.Ca@Sun.COM 		    "job-attributes-group", &op);
4622264Sjacobs 		copy_attributes(&j->attributes, op);
4632264Sjacobs 	}
4642264Sjacobs 	papiAttributeListFree(response);
4652264Sjacobs 
4662264Sjacobs 	return (result);
4672264Sjacobs }
4682264Sjacobs 
4692264Sjacobs papi_status_t
4702264Sjacobs papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
4712264Sjacobs 		char **requested_attrs,
4722264Sjacobs 		papi_job_t *job)
4732264Sjacobs {
4742264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
4752264Sjacobs 	service_t *svc = handle;
4762264Sjacobs 	job_t *j = NULL;
4772264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
4782264Sjacobs 
4792264Sjacobs 	if ((svc == NULL) || (printer == NULL))
4802264Sjacobs 		return (PAPI_BAD_ARGUMENT);
4812264Sjacobs 
4822264Sjacobs 	/* if we are already connected, use that connection. */
4832264Sjacobs 	if (svc->connection == NULL)
4842264Sjacobs 		if ((result = service_connect(svc, printer)) != PAPI_OK)
4852264Sjacobs 			return (result);
4862264Sjacobs 
4872264Sjacobs 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
4882264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
4892264Sjacobs 
4902264Sjacobs 	ipp_initialize_request(svc, &request, OPID_GET_JOB_ATTRIBUTES);
4912264Sjacobs 
4923917Sjacobs 	ipp_initialize_operational_attributes(svc, &op, printer, job_id);
4932264Sjacobs 
4942264Sjacobs 	if (requested_attrs != NULL) {
4952264Sjacobs 		int i;
4962264Sjacobs 
4972264Sjacobs 		for (i = 0; requested_attrs[i] != NULL; i++)
4982264Sjacobs 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
4998569SJonathan.Ca@Sun.COM 			    "requested-attributes", requested_attrs[i]);
5002264Sjacobs 	}
5012264Sjacobs 
5022264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
5038569SJonathan.Ca@Sun.COM 	    "operational-attributes-group", op);
5042264Sjacobs 	papiAttributeListFree(op);
5052264Sjacobs 	result = ipp_send_request(svc, request, &response);
5062264Sjacobs 	papiAttributeListFree(request);
5072264Sjacobs 
5082264Sjacobs 	op = NULL;
5092264Sjacobs 	papiAttributeListGetCollection(response, NULL,
5108569SJonathan.Ca@Sun.COM 	    "job-attributes-group", &op);
5112264Sjacobs 	copy_attributes(&j->attributes, op);
5122264Sjacobs 	papiAttributeListFree(response);
5132264Sjacobs 
5142264Sjacobs 	return (result);
5152264Sjacobs }
5162264Sjacobs 
5172264Sjacobs /* papiJob{Cancel|Hold|Release|Restart|Promote} are all the same */
5182264Sjacobs static papi_status_t
5192264Sjacobs _job_cancel_hold_release_restart_promote(papi_service_t handle,
5202264Sjacobs 		char *printer, int32_t job_id, uint16_t type)
5212264Sjacobs {
5222264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
5232264Sjacobs 	service_t *svc = handle;
5242264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
5252264Sjacobs 
5262264Sjacobs 	if ((svc == NULL) || (printer == NULL) || (job_id < 0))
5272264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5282264Sjacobs 
5292264Sjacobs 	/* if we are already connected, use that connection. */
5302264Sjacobs 	if (svc->connection == NULL)
5312264Sjacobs 		if ((result = service_connect(svc, printer)) != PAPI_OK)
5322264Sjacobs 			return (result);
5332264Sjacobs 
5342264Sjacobs 	ipp_initialize_request(svc, &request, type);
5352264Sjacobs 
5363917Sjacobs 	ipp_initialize_operational_attributes(svc, &op, printer, job_id);
5372264Sjacobs 
5382264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
5398569SJonathan.Ca@Sun.COM 	    "operational-attributes-group", op);
5402264Sjacobs 	papiAttributeListFree(op);
5412264Sjacobs 	result = ipp_send_request(svc, request, &response);
5422264Sjacobs 	papiAttributeListFree(request);
5432264Sjacobs 	papiAttributeListFree(response);
5442264Sjacobs 
5452264Sjacobs 	return (result);
5462264Sjacobs }
5472264Sjacobs 
5482264Sjacobs papi_status_t
5492264Sjacobs papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
5502264Sjacobs {
5512264Sjacobs 	return (_job_cancel_hold_release_restart_promote(handle, printer,
5528569SJonathan.Ca@Sun.COM 	    job_id, OPID_CANCEL_JOB));
5532264Sjacobs }
5542264Sjacobs 
5552264Sjacobs 
5562264Sjacobs papi_status_t
5572264Sjacobs papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
5582264Sjacobs {
5592264Sjacobs 	return (_job_cancel_hold_release_restart_promote(handle, printer,
5608569SJonathan.Ca@Sun.COM 	    job_id, OPID_HOLD_JOB));
5612264Sjacobs }
5622264Sjacobs 
5632264Sjacobs papi_status_t
5642264Sjacobs papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
5652264Sjacobs {
5662264Sjacobs 	return (_job_cancel_hold_release_restart_promote(handle, printer,
5678569SJonathan.Ca@Sun.COM 	    job_id, OPID_RELEASE_JOB));
5682264Sjacobs }
5692264Sjacobs 
5702264Sjacobs papi_status_t
5712264Sjacobs papiJobRestart(papi_service_t handle, char *printer, int32_t job_id)
5722264Sjacobs {
5732264Sjacobs 	return (_job_cancel_hold_release_restart_promote(handle, printer,
5748569SJonathan.Ca@Sun.COM 	    job_id, OPID_RESTART_JOB));
5752264Sjacobs }
5762264Sjacobs 
5772264Sjacobs papi_status_t
5782264Sjacobs papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
5792264Sjacobs {
5802264Sjacobs 	return (_job_cancel_hold_release_restart_promote(handle, printer,
5818569SJonathan.Ca@Sun.COM 	    job_id, OPID_PROMOTE_JOB));
5822264Sjacobs }
5832264Sjacobs 
5842264Sjacobs papi_status_t
5852264Sjacobs papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
5862264Sjacobs 		char *destination)
5872264Sjacobs {
5882264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
5892264Sjacobs 	service_t *svc = handle;
5902264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
5912264Sjacobs 
5922264Sjacobs 	if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
5932264Sjacobs 	    (destination == NULL))
5942264Sjacobs 		return (PAPI_BAD_ARGUMENT);
5952264Sjacobs 
5962264Sjacobs 	/* if we are already connected, use that connection. */
5972264Sjacobs 	if (svc->connection == NULL)
5982264Sjacobs 		if ((result = service_connect(svc, printer)) != PAPI_OK)
5992264Sjacobs 			return (result);
6002264Sjacobs 
6012264Sjacobs 	ipp_initialize_request(svc, &request, OPID_CUPS_MOVE_JOB);
6022264Sjacobs 
6033917Sjacobs 	ipp_initialize_operational_attributes(svc, &op, printer, job_id);
6042264Sjacobs 
6052264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
6068569SJonathan.Ca@Sun.COM 	    "operational-attributes-group", op);
6072264Sjacobs 	papiAttributeListFree(op);
6082264Sjacobs 
6092264Sjacobs 	op = NULL;
6102264Sjacobs 	papiAttributeListAddString(&op, PAPI_ATTR_EXCL,
6118569SJonathan.Ca@Sun.COM 	    "job-printer-uri", destination);
6122264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
6138569SJonathan.Ca@Sun.COM 	    "job-attributes-group", op);
6142264Sjacobs 	papiAttributeListFree(op);
6152264Sjacobs 
6162264Sjacobs 	result = ipp_send_request(svc, request, &response);
6172264Sjacobs 	papiAttributeListFree(request);
6182264Sjacobs 	papiAttributeListFree(response);
6192264Sjacobs 
6202264Sjacobs 	return (result);
6212264Sjacobs }
6222264Sjacobs 
6232264Sjacobs papi_status_t
6242264Sjacobs papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
6252264Sjacobs 		papi_attribute_t **attributes, papi_job_t *job)
6262264Sjacobs {
6272264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
6282264Sjacobs 	service_t *svc = handle;
6292264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
6302264Sjacobs 	job_t *j = NULL;
6312264Sjacobs 
6322264Sjacobs 	if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
6332264Sjacobs 	    (attributes == NULL))
6342264Sjacobs 		return (PAPI_BAD_ARGUMENT);
6352264Sjacobs 
6362264Sjacobs 	if ((*job = j = calloc(1, sizeof (*j))) == NULL)
6372264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
6382264Sjacobs 
6392264Sjacobs 	/* if we are already connected, use that connection. */
6402264Sjacobs 	if (svc->connection == NULL)
6412264Sjacobs 		if ((result = service_connect(svc, printer)) != PAPI_OK)
6422264Sjacobs 			return (result);
6432264Sjacobs 
6442264Sjacobs 	ipp_initialize_request(svc, &request, OPID_SET_JOB_ATTRIBUTES);
6452264Sjacobs 
6463917Sjacobs 	ipp_initialize_operational_attributes(svc, &op, printer, job_id);
6472264Sjacobs 
6482264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
6498569SJonathan.Ca@Sun.COM 	    "operational-attributes-group", op);
6502264Sjacobs 	papiAttributeListFree(op);
6512264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
6528569SJonathan.Ca@Sun.COM 	    "job-attributes-group", attributes);
6532264Sjacobs 	result = ipp_send_request(svc, request, &response);
6542264Sjacobs 	papiAttributeListFree(request);
6552264Sjacobs 
6562264Sjacobs 	op = NULL;
6572264Sjacobs 	papiAttributeListGetCollection(response, NULL,
6588569SJonathan.Ca@Sun.COM 	    "job-attributes-group", &op);
6592264Sjacobs 	copy_attributes(&j->attributes, op);
6602264Sjacobs 	papiAttributeListFree(response);
6612264Sjacobs 
6622264Sjacobs 	return (result);
6632264Sjacobs }
664