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: printer.c 146 2006-03-24 00:26:54Z 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 <papi_impl.h>
36*2264Sjacobs 
37*2264Sjacobs #include <config-site.h>
38*2264Sjacobs 
39*2264Sjacobs void
40*2264Sjacobs papiPrinterFree(papi_printer_t printer)
41*2264Sjacobs {
42*2264Sjacobs 	printer_t *tmp = printer;
43*2264Sjacobs 
44*2264Sjacobs 	if (tmp != NULL) {
45*2264Sjacobs 		if (tmp->attributes != NULL)
46*2264Sjacobs 			papiAttributeListFree(tmp->attributes);
47*2264Sjacobs 		free(tmp);
48*2264Sjacobs 	}
49*2264Sjacobs }
50*2264Sjacobs 
51*2264Sjacobs void
52*2264Sjacobs papiPrinterListFree(papi_printer_t *printers)
53*2264Sjacobs {
54*2264Sjacobs 	if (printers != NULL) {
55*2264Sjacobs 		int i;
56*2264Sjacobs 
57*2264Sjacobs 		for (i = 0; printers[i] != NULL; i++)
58*2264Sjacobs 			papiPrinterFree(printers[i]);
59*2264Sjacobs 		free(printers);
60*2264Sjacobs 	}
61*2264Sjacobs }
62*2264Sjacobs 
63*2264Sjacobs /*
64*2264Sjacobs  * Enumeration of printers is not part of the IPP specification, so many
65*2264Sjacobs  * servers will probably not respond back with a list of printers, but
66*2264Sjacobs  * CUPS has implemented an extension to IPP to enumerate printers and
67*2264Sjacobs  * classes. the Apache/mod_ipp IPP listener module available in Solaris
68*2264Sjacobs  * implements this IPP extension, so CUPS and Solaris can provide this
69*2264Sjacobs  * to IPP clients.
70*2264Sjacobs  */
71*2264Sjacobs #ifndef	OPID_CUPS_GET_PRINTERS		/* for servers that will enumerate */
72*2264Sjacobs #define	OPID_CUPS_GET_PRINTERS		0x4002
73*2264Sjacobs #endif	/* OPID_CUPS_GET_PRINTERS */
74*2264Sjacobs #ifndef	OPID_CUPS_DELETE_PRINTER	/* for servers that can delete */
75*2264Sjacobs #define	OPID_CUPS_DELETE_PRINTER	0x4004
76*2264Sjacobs #endif	/* OPID_CUPS_DELETE_PRINTER */
77*2264Sjacobs #ifndef	OPID_CUPS_GET_CLASSES		/* for servers that will enumerate */
78*2264Sjacobs #define	OPID_CUPS_GET_CLASSES		0x4005
79*2264Sjacobs #endif	/* OPID_CUPS_GET_CLASSES */
80*2264Sjacobs 
81*2264Sjacobs papi_status_t
82*2264Sjacobs papiPrintersList(papi_service_t handle, char **requested_attrs,
83*2264Sjacobs 		papi_filter_t *filter, papi_printer_t **printers)
84*2264Sjacobs {
85*2264Sjacobs 	papi_status_t status, result = PAPI_INTERNAL_ERROR;
86*2264Sjacobs 	service_t *svc = handle;
87*2264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
88*2264Sjacobs 	void *iter = NULL;
89*2264Sjacobs 
90*2264Sjacobs 	if ((svc == NULL) || (printers == NULL))
91*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
92*2264Sjacobs 
93*2264Sjacobs 	/* if we are already connected, use that connection. */
94*2264Sjacobs 	if (svc->connection == NULL)
95*2264Sjacobs 		if ((result = service_connect(svc, DEFAULT_DEST)) != PAPI_OK)
96*2264Sjacobs 			return (result);
97*2264Sjacobs 	ipp_initialize_request(svc, &request, OPID_CUPS_GET_PRINTERS);
98*2264Sjacobs 
99*2264Sjacobs 	ipp_initialize_operational_attributes(svc, &op, NULL);
100*2264Sjacobs 
101*2264Sjacobs 	if (requested_attrs != NULL) {
102*2264Sjacobs 		int i;
103*2264Sjacobs 
104*2264Sjacobs 		for (i = 0; requested_attrs[i] != NULL; i++)
105*2264Sjacobs 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
106*2264Sjacobs 				"requested-attributes", requested_attrs[i]);
107*2264Sjacobs 	}
108*2264Sjacobs 
109*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
110*2264Sjacobs 			"operational-attributes-group", op);
111*2264Sjacobs 	papiAttributeListFree(op);
112*2264Sjacobs 	result = ipp_send_request(svc, request, &response);
113*2264Sjacobs 	papiAttributeListFree(request);
114*2264Sjacobs 
115*2264Sjacobs 	op = NULL;
116*2264Sjacobs 	for (status = papiAttributeListGetCollection(response, &iter,
117*2264Sjacobs 				"printer-attributes-group", &op);
118*2264Sjacobs 	     status == PAPI_OK;
119*2264Sjacobs 	     status = papiAttributeListGetCollection(response, &iter,
120*2264Sjacobs 				NULL, &op)) {
121*2264Sjacobs 		printer_t *p = NULL;
122*2264Sjacobs 
123*2264Sjacobs 		if ((p = calloc(1, sizeof (*p))) == NULL)
124*2264Sjacobs 			return (PAPI_TEMPORARY_ERROR);
125*2264Sjacobs 
126*2264Sjacobs 		copy_attributes(&p->attributes, op);
127*2264Sjacobs 		op = NULL;
128*2264Sjacobs 		list_append(printers, p);
129*2264Sjacobs 	}
130*2264Sjacobs 	papiAttributeListFree(response);
131*2264Sjacobs 
132*2264Sjacobs 	return (result);
133*2264Sjacobs }
134*2264Sjacobs 
135*2264Sjacobs papi_status_t
136*2264Sjacobs papiPrinterQuery(papi_service_t handle, char *name,
137*2264Sjacobs 		char **requested_attrs,
138*2264Sjacobs 		papi_attribute_t **job_attributes,
139*2264Sjacobs 		papi_printer_t *printer)
140*2264Sjacobs {
141*2264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
142*2264Sjacobs 	service_t *svc = handle;
143*2264Sjacobs 	printer_t *p = NULL;
144*2264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
145*2264Sjacobs 
146*2264Sjacobs 	if ((svc == NULL) || (name == NULL) || (printer == NULL))
147*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
148*2264Sjacobs 
149*2264Sjacobs 	/* if we are already connected, use that connection. */
150*2264Sjacobs 	if (svc->connection == NULL)
151*2264Sjacobs 		if ((result = service_connect(svc, name)) != PAPI_OK)
152*2264Sjacobs 			return (result);
153*2264Sjacobs 
154*2264Sjacobs 	if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
155*2264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
156*2264Sjacobs 
157*2264Sjacobs 	ipp_initialize_request(svc, &request, OPID_GET_PRINTER_ATTRIBUTES);
158*2264Sjacobs 
159*2264Sjacobs 	ipp_initialize_operational_attributes(svc, &op, NULL);
160*2264Sjacobs 	ipp_add_printer_uri(svc, name, &op);
161*2264Sjacobs 
162*2264Sjacobs 	if (requested_attrs != NULL) {
163*2264Sjacobs 		int i;
164*2264Sjacobs 
165*2264Sjacobs 		for (i = 0; requested_attrs[i] != NULL; i++)
166*2264Sjacobs 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
167*2264Sjacobs 				"requested-attributes", requested_attrs[i]);
168*2264Sjacobs 	}
169*2264Sjacobs 
170*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
171*2264Sjacobs 			"operational-attributes-group", op);
172*2264Sjacobs 	papiAttributeListFree(op);
173*2264Sjacobs 	result = ipp_send_request(svc, request, &response);
174*2264Sjacobs 	papiAttributeListFree(request);
175*2264Sjacobs 
176*2264Sjacobs 	op = NULL;
177*2264Sjacobs 	papiAttributeListGetCollection(response, NULL,
178*2264Sjacobs 			"printer-attributes-group", &op);
179*2264Sjacobs 	copy_attributes(&p->attributes, op);
180*2264Sjacobs 	papiAttributeListFree(response);
181*2264Sjacobs 
182*2264Sjacobs 	return (result);
183*2264Sjacobs }
184*2264Sjacobs 
185*2264Sjacobs static papi_status_t
186*2264Sjacobs _printer_enable_disable_pause_resume_delete(papi_service_t handle, char *name,
187*2264Sjacobs 		char *message, uint16_t type)
188*2264Sjacobs {
189*2264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
190*2264Sjacobs 	service_t *svc = handle;
191*2264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
192*2264Sjacobs 
193*2264Sjacobs 	if ((svc == NULL) || (name == NULL))
194*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
195*2264Sjacobs 
196*2264Sjacobs 	/* if we are already connected, use that connection. */
197*2264Sjacobs 	if (svc->connection == NULL)
198*2264Sjacobs 		if ((result = service_connect(svc, name)) != PAPI_OK)
199*2264Sjacobs 			return (result);
200*2264Sjacobs 
201*2264Sjacobs 	ipp_initialize_request(svc, &request, type);
202*2264Sjacobs 
203*2264Sjacobs 	ipp_initialize_operational_attributes(svc, &op, NULL);
204*2264Sjacobs 	ipp_add_printer_uri(svc, name, &op);
205*2264Sjacobs 
206*2264Sjacobs 	switch (type) {
207*2264Sjacobs 	case OPID_DISABLE_PRINTER:
208*2264Sjacobs 		papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
209*2264Sjacobs 				"printer-message-from-operator", message);
210*2264Sjacobs 		break;
211*2264Sjacobs 	case OPID_PAUSE_PRINTER:
212*2264Sjacobs 		papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
213*2264Sjacobs 				"printer-state-message", message);
214*2264Sjacobs 		break;
215*2264Sjacobs 	default: /* a message value is of no use */
216*2264Sjacobs 		break;
217*2264Sjacobs 	}
218*2264Sjacobs 
219*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
220*2264Sjacobs 			"operational-attributes-group", op);
221*2264Sjacobs 	papiAttributeListFree(op);
222*2264Sjacobs 	result = ipp_send_request(svc, request, &response);
223*2264Sjacobs 	papiAttributeListFree(request);
224*2264Sjacobs 	papiAttributeListFree(response);
225*2264Sjacobs 
226*2264Sjacobs 	return (result);
227*2264Sjacobs }
228*2264Sjacobs 
229*2264Sjacobs papi_status_t
230*2264Sjacobs papiPrinterEnable(papi_service_t handle, char *name)
231*2264Sjacobs {
232*2264Sjacobs 	return (_printer_enable_disable_pause_resume_delete(handle, name,
233*2264Sjacobs 				NULL, OPID_ENABLE_PRINTER));
234*2264Sjacobs }
235*2264Sjacobs 
236*2264Sjacobs papi_status_t
237*2264Sjacobs papiPrinterResume(papi_service_t handle, char *name)
238*2264Sjacobs {
239*2264Sjacobs 	return (_printer_enable_disable_pause_resume_delete(handle, name,
240*2264Sjacobs 				NULL, OPID_RESUME_PRINTER));
241*2264Sjacobs }
242*2264Sjacobs 
243*2264Sjacobs papi_status_t
244*2264Sjacobs papiPrinterPause(papi_service_t handle, char *name, char *message)
245*2264Sjacobs {
246*2264Sjacobs 	return (_printer_enable_disable_pause_resume_delete(handle, name,
247*2264Sjacobs 				message, OPID_PAUSE_PRINTER));
248*2264Sjacobs }
249*2264Sjacobs 
250*2264Sjacobs papi_status_t
251*2264Sjacobs papiPrinterDisable(papi_service_t handle, char *name, char *message)
252*2264Sjacobs {
253*2264Sjacobs 	return (_printer_enable_disable_pause_resume_delete(handle, name,
254*2264Sjacobs 				message, OPID_PAUSE_PRINTER));
255*2264Sjacobs }
256*2264Sjacobs 
257*2264Sjacobs /*
258*2264Sjacobs  * there is no IPP create operation, the set-printer-attibutes operation
259*2264Sjacobs  * is the closest we have, so we will assume that the server will create
260*2264Sjacobs  * a printer and set attributes if there is none.
261*2264Sjacobs  */
262*2264Sjacobs papi_status_t
263*2264Sjacobs papiPrinterAdd(papi_service_t handle, char *name,
264*2264Sjacobs 		papi_attribute_t **attributes, papi_printer_t *printer)
265*2264Sjacobs {
266*2264Sjacobs 	return (papiPrinterModify(handle, name, attributes, printer));
267*2264Sjacobs }
268*2264Sjacobs 
269*2264Sjacobs papi_status_t
270*2264Sjacobs papiPrinterModify(papi_service_t handle, char *name,
271*2264Sjacobs 		papi_attribute_t **attributes, papi_printer_t *printer)
272*2264Sjacobs {
273*2264Sjacobs 	papi_status_t result = PAPI_INTERNAL_ERROR;
274*2264Sjacobs 	service_t *svc = handle;
275*2264Sjacobs 	printer_t *p = NULL;
276*2264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
277*2264Sjacobs 
278*2264Sjacobs 	if ((svc == NULL) || (name == NULL) || (printer == NULL))
279*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
280*2264Sjacobs 
281*2264Sjacobs 	/* if we are already connected, use that connection. */
282*2264Sjacobs 	if (svc->connection == NULL)
283*2264Sjacobs 		if ((result = service_connect(svc, name)) != PAPI_OK)
284*2264Sjacobs 			return (result);
285*2264Sjacobs 
286*2264Sjacobs 	if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
287*2264Sjacobs 		return (PAPI_TEMPORARY_ERROR);
288*2264Sjacobs 
289*2264Sjacobs 	ipp_initialize_request(svc, &request, OPID_SET_PRINTER_ATTRIBUTES);
290*2264Sjacobs 
291*2264Sjacobs 	ipp_initialize_operational_attributes(svc, &op, NULL);
292*2264Sjacobs 	ipp_add_printer_uri(svc, name, &op);
293*2264Sjacobs 
294*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
295*2264Sjacobs 			"operational-attributes-group", op);
296*2264Sjacobs 	papiAttributeListFree(op);
297*2264Sjacobs 
298*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
299*2264Sjacobs 			"printer-attributes-group", attributes);
300*2264Sjacobs 	result = ipp_send_request(svc, request, &response);
301*2264Sjacobs 	papiAttributeListFree(request);
302*2264Sjacobs 
303*2264Sjacobs 	op = NULL;
304*2264Sjacobs 	papiAttributeListGetCollection(response, NULL,
305*2264Sjacobs 			"printer-attributes-group", &op);
306*2264Sjacobs 	copy_attributes(&p->attributes, op);
307*2264Sjacobs 	papiAttributeListFree(response);
308*2264Sjacobs 
309*2264Sjacobs 	return (result);
310*2264Sjacobs }
311*2264Sjacobs 
312*2264Sjacobs papi_status_t
313*2264Sjacobs papiPrinterRemove(papi_service_t handle, char *name)
314*2264Sjacobs {
315*2264Sjacobs 	return (_printer_enable_disable_pause_resume_delete(handle, name,
316*2264Sjacobs 				NULL, OPID_CUPS_DELETE_PRINTER));
317*2264Sjacobs }
318*2264Sjacobs 
319*2264Sjacobs papi_status_t
320*2264Sjacobs papiPrinterPurgeJobs(papi_service_t handle, char *name,
321*2264Sjacobs 		papi_job_t **jobs)
322*2264Sjacobs {
323*2264Sjacobs 	papi_status_t status, result = PAPI_INTERNAL_ERROR;
324*2264Sjacobs 	service_t *svc = handle;
325*2264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
326*2264Sjacobs 	void *iter = NULL;
327*2264Sjacobs 
328*2264Sjacobs 
329*2264Sjacobs 	if ((svc == NULL) || (name == NULL))
330*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
331*2264Sjacobs 
332*2264Sjacobs 	/* if we are already connected, use that connection. */
333*2264Sjacobs 	if (svc->connection == NULL)
334*2264Sjacobs 		if ((result = service_connect(svc, name)) != PAPI_OK)
335*2264Sjacobs 			return (result);
336*2264Sjacobs 
337*2264Sjacobs 	ipp_initialize_request(svc, &request, OPID_PURGE_JOBS);
338*2264Sjacobs 
339*2264Sjacobs 	ipp_initialize_operational_attributes(svc, &op, NULL);
340*2264Sjacobs 	ipp_add_printer_uri(svc, name, &op);
341*2264Sjacobs 
342*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
343*2264Sjacobs 			"operational-attributes-group", op);
344*2264Sjacobs 	papiAttributeListFree(op);
345*2264Sjacobs 	result = ipp_send_request(svc, request, &response);
346*2264Sjacobs 	papiAttributeListFree(request);
347*2264Sjacobs 
348*2264Sjacobs 	op = NULL;
349*2264Sjacobs 	for (status = papiAttributeListGetCollection(response, &iter,
350*2264Sjacobs 				"job-attributes-group", &op);
351*2264Sjacobs 	     status == PAPI_OK;
352*2264Sjacobs 	     status = papiAttributeListGetCollection(response, &iter,
353*2264Sjacobs 				NULL, &op)) {
354*2264Sjacobs 		job_t *j = NULL;
355*2264Sjacobs 
356*2264Sjacobs 		if ((j = calloc(1, sizeof (*j))) == NULL)
357*2264Sjacobs 			return (PAPI_TEMPORARY_ERROR);
358*2264Sjacobs 
359*2264Sjacobs 		copy_attributes(&j->attributes, op);
360*2264Sjacobs 		op = NULL;
361*2264Sjacobs 		list_append(jobs, j);
362*2264Sjacobs 	}
363*2264Sjacobs 	papiAttributeListFree(response);
364*2264Sjacobs 
365*2264Sjacobs 	return (result);
366*2264Sjacobs }
367*2264Sjacobs 
368*2264Sjacobs papi_status_t
369*2264Sjacobs papiPrinterListJobs(papi_service_t handle, char *name,
370*2264Sjacobs 		char **requested_attrs, int type_mask,
371*2264Sjacobs 		int max_num_jobs, papi_job_t **jobs)
372*2264Sjacobs {
373*2264Sjacobs 	papi_status_t status, result = PAPI_INTERNAL_ERROR;
374*2264Sjacobs 	service_t *svc = handle;
375*2264Sjacobs 	papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
376*2264Sjacobs 	void *iter = NULL;
377*2264Sjacobs 
378*2264Sjacobs 	if ((svc == NULL) || (name == NULL))
379*2264Sjacobs 		return (PAPI_BAD_ARGUMENT);
380*2264Sjacobs 
381*2264Sjacobs 	/* if we are already connected, use that connection. */
382*2264Sjacobs 	if (svc->connection == NULL)
383*2264Sjacobs 		if ((result = service_connect(svc, name)) != PAPI_OK)
384*2264Sjacobs 			return (result);
385*2264Sjacobs 
386*2264Sjacobs 	ipp_initialize_request(svc, &request, OPID_GET_JOBS);
387*2264Sjacobs 
388*2264Sjacobs 	ipp_initialize_operational_attributes(svc, &op, NULL);
389*2264Sjacobs 	ipp_add_printer_uri(svc, name, &op);
390*2264Sjacobs 
391*2264Sjacobs 	if (requested_attrs != NULL) {
392*2264Sjacobs 		int i;
393*2264Sjacobs 
394*2264Sjacobs 		for (i = 0; requested_attrs[i] != NULL; i++)
395*2264Sjacobs 			papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
396*2264Sjacobs 				"requested-attributes", requested_attrs[i]);
397*2264Sjacobs 	}
398*2264Sjacobs 
399*2264Sjacobs 	papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
400*2264Sjacobs 			"operational-attributes-group", op);
401*2264Sjacobs 	papiAttributeListFree(op);
402*2264Sjacobs 	result = ipp_send_request(svc, request, &response);
403*2264Sjacobs 	papiAttributeListFree(request);
404*2264Sjacobs 
405*2264Sjacobs 	op = NULL;
406*2264Sjacobs 	for (status = papiAttributeListGetCollection(response, &iter,
407*2264Sjacobs 				"job-attributes-group", &op);
408*2264Sjacobs 	     status == PAPI_OK;
409*2264Sjacobs 	     status = papiAttributeListGetCollection(response, &iter,
410*2264Sjacobs 				NULL, &op)) {
411*2264Sjacobs 		job_t *j = NULL;
412*2264Sjacobs 
413*2264Sjacobs 		if ((j = calloc(1, sizeof (*j))) == NULL)
414*2264Sjacobs 			return (PAPI_TEMPORARY_ERROR);
415*2264Sjacobs 
416*2264Sjacobs 		copy_attributes(&j->attributes, op);
417*2264Sjacobs 		op = NULL;
418*2264Sjacobs 		list_append(jobs, j);
419*2264Sjacobs 	}
420*2264Sjacobs 	papiAttributeListFree(response);
421*2264Sjacobs 
422*2264Sjacobs 	return (result);
423*2264Sjacobs }
424*2264Sjacobs 
425*2264Sjacobs papi_attribute_t **
426*2264Sjacobs papiPrinterGetAttributeList(papi_printer_t printer)
427*2264Sjacobs {
428*2264Sjacobs 	papi_attribute_t **result = NULL;
429*2264Sjacobs 	printer_t *p = printer;
430*2264Sjacobs 
431*2264Sjacobs 	if (p != NULL)
432*2264Sjacobs 		result = p->attributes;
433*2264Sjacobs 
434*2264Sjacobs 	return (result);
435*2264Sjacobs }
436